jsintern.c 3.2 KB

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