ref: adbbeec67255f04049dbf28a3fe7573e8248f97d
parent: ce69f95ff02a19672e65a833df19952bbaa44f00
author: Tor Andersson <tor.andersson@artifex.com>
date: Sat Dec 28 13:22:09 EST 2013
String interning table.
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-SRCS := js-state.c js-load.c js-lex.c js-parse.c
+SRCS := js-state.c js-string.c js-load.c js-lex.c js-parse.c
HDRS := js.h js-parse.h
OBJS := $(SRCS:%.c=build/%.o)
--- /dev/null
+++ b/js-string.c
@@ -1,0 +1,107 @@
+#include "js.h"
+
+/* Use an AA-tree to quickly look up interned strings. */
+
+struct js_StringNode
+{
+ const char *string;
+ js_StringNode *left, *right;
+ int level;
+};
+
+static js_StringNode sentinel = { "", &sentinel, &sentinel, 0 };
+
+static js_StringNode *makestringnode(const char *string, const char **out)
+{
+ js_StringNode *node = malloc(sizeof(js_StringNode));
+ node->string = *out = strdup(string);
+ node->left = node->right = &sentinel;
+ node->level = 1;
+ return node;
+}
+
+static const char *lookup(js_StringNode *node, const char *string)
+{
+ if (node && node != &sentinel) {
+ int c = strcmp(string, node->string);
+ if (c == 0)
+ return node->string;
+ else if (c < 0)
+ return lookup(node->left, string);
+ else
+ return lookup(node->right, string);
+ }
+ return NULL;
+}
+
+static js_StringNode *skew(js_StringNode *node)
+{
+ if (node->level != 0) {
+ if (node->left->level == node->level) {
+ js_StringNode *save = node;
+ node = node->left;
+ save->left = node->right;
+ node->right = save;
+ }
+ node->right = skew(node->right);
+ }
+ return node;
+}
+
+static js_StringNode *split(js_StringNode *node)
+{
+ if (node->level != 0 && node->right->right->level == node->level) {
+ js_StringNode *save = node;
+ node = node->right;
+ save->right = node->left;
+ node->left = save;
+ node->level++;
+ node->right = split(node->right);
+ }
+ return node;
+}
+
+static js_StringNode *insert(js_StringNode *node, const char *string, const char **out)
+{
+ if (node && node != &sentinel) {
+ int c = strcmp(string, node->string);
+ if (c < 0)
+ node->left = insert(node->left, string, out);
+ else
+ node->right = insert(node->right, string, out);
+ node = skew(node);
+ node = split(node);
+ return node;
+ } else {
+ return makestringnode(string, out);
+ }
+}
+
+static void printstringnode(js_StringNode *node, int level)
+{
+ int i;
+ if (node->left != &sentinel)
+ printstringnode(node->left, level + 1);
+ for (i = 0; i < level; i++)
+ putchar(' ');
+ printf("'%s' (%d)\n", node->string, node->level);
+ if (node->right != &sentinel)
+ printstringnode(node->right, level + 1);
+}
+
+void js_printstringtree(js_State *J)
+{
+ js_StringNode *root = J->strings;
+ printf("--- string dump ---\n");
+ if (root && root != &sentinel)
+ printstringnode(root, 0);
+ printf("---\n");
+}
+
+const char *js_intern(js_State *J, const char *s)
+{
+ const char *a = lookup(J->strings, s);
+ if (!a)
+ J->strings = insert(J->strings, s, &a);
+ return a;
+}
--- a/js.h
+++ b/js.h
@@ -9,6 +9,7 @@
#include <math.h>
typedef struct js_State js_State;
+typedef struct js_StringNode js_StringNode;
typedef int (*js_CFunction)(js_State *J);
@@ -20,6 +21,8 @@
int js_loadstring(js_State *J, const char *s);
int js_loadfile(js_State *J, const char *filename);
+const char *js_intern(js_State *J, const char *s);
+
/* private */
void jsP_initlex(js_State *J, const char *source);
@@ -26,6 +29,8 @@
int jsP_lex(js_State *J);
int jsP_parse(js_State *J);
+void js_printstringtree(js_State *J);
+
struct js_State
{
const char *yysource;
@@ -37,6 +42,8 @@
int lasttoken;
int newline;
int strict;
+
+ js_StringNode *strings;
};
#endif