1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#include "jsi.h"
/* Dynamically grown string buffer */
void js_putc(js_State *J, js_Buffer **sbp, int c)
{
js_Buffer *sb = *sbp;
if (!sb) {
sb = js_malloc(J, sizeof *sb);
sb->n = 0;
sb->m = sizeof sb->s;
*sbp = sb;
} else if (sb->n == sb->m) {
sb = js_realloc(J, sb, (sb->m *= 2) + soffsetof(js_Buffer, s));
*sbp = sb;
}
sb->s[sb->n++] = c;
}
void js_puts(js_State *J, js_Buffer **sb, const char *s)
{
while (*s)
js_putc(J, sb, *s++);
}
void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e)
{
while (s < e)
js_putc(J, sb, *s++);
}
/* Use an AA-tree to quickly look up interned strings. */
struct js_StringNode
{
js_StringNode *left, *right;
int level;
char string[1];
};
static js_StringNode jsS_sentinel = { &jsS_sentinel, &jsS_sentinel, 0, ""};
static js_StringNode *jsS_newstringnode(js_State *J, const char *string, const char **result)
{
int n = strlen(string);
js_StringNode *node = js_malloc(J, soffsetof(js_StringNode, string) + n + 1);
node->left = node->right = &jsS_sentinel;
node->level = 1;
memcpy(node->string, string, n + 1);
return *result = node->string, node;
}
static js_StringNode *jsS_skew(js_StringNode *node)
{
if (node->left->level == node->level) {
js_StringNode *temp = node;
node = node->left;
temp->left = node->right;
node->right = temp;
}
return node;
}
static js_StringNode *jsS_split(js_StringNode *node)
{
if (node->right->right->level == node->level) {
js_StringNode *temp = node;
node = node->right;
temp->right = node->left;
node->left = temp;
++node->level;
}
return node;
}
static js_StringNode *jsS_insert(js_State *J, js_StringNode *node, const char *string, const char **result)
{
if (node != &jsS_sentinel) {
int c = strcmp(string, node->string);
if (c < 0)
node->left = jsS_insert(J, node->left, string, result);
else if (c > 0)
node->right = jsS_insert(J, node->right, string, result);
else
return *result = node->string, node;
node = jsS_skew(node);
node = jsS_split(node);
return node;
}
return jsS_newstringnode(J, string, result);
}
static void dumpstringnode(js_StringNode *node, int level)
{
int i;
if (node->left != &jsS_sentinel)
dumpstringnode(node->left, level + 1);
printf("%d: ", node->level);
for (i = 0; i < level; ++i)
putchar('\t');
printf("'%s'\n", node->string);
if (node->right != &jsS_sentinel)
dumpstringnode(node->right, level + 1);
}
void jsS_dumpstrings(js_State *J)
{
js_StringNode *root = J->strings;
printf("interned strings {\n");
if (root && root != &jsS_sentinel)
dumpstringnode(root, 1);
printf("}\n");
}
static void jsS_freestringnode(js_State *J, js_StringNode *node)
{
if (node->left != &jsS_sentinel) jsS_freestringnode(J, node->left);
if (node->right != &jsS_sentinel) jsS_freestringnode(J, node->right);
js_free(J, node);
}
void jsS_freestrings(js_State *J)
{
if (J->strings && J->strings != &jsS_sentinel)
jsS_freestringnode(J, J->strings);
}
const char *js_intern(js_State *J, const char *s)
{
const char *result;
if (!J->strings)
J->strings = &jsS_sentinel;
J->strings = jsS_insert(J, J->strings, s, &result);
return result;
}
|