lstring.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. ** $Id: lstring.c,v 1.1 1997/08/14 20:23:30 roberto Exp $
  3. ** String table (keep all strings handled by Lua)
  4. ** See Copyright Notice in lua.h
  5. */
  6. #include <string.h>
  7. #include "lmem.h"
  8. #include "lobject.h"
  9. #include "lstring.h"
  10. #include "lua.h"
  11. #define NUM_HASHS 61
  12. typedef struct {
  13. int size;
  14. int nuse; /* number of elements (including EMPTYs) */
  15. TaggedString **hash;
  16. } stringtable;
  17. static stringtable string_root[NUM_HASHS] = {
  18. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  19. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  20. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  21. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  22. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  23. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  24. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  25. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  26. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  27. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  28. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  29. {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL}, {0, 0, NULL},
  30. {0, 0, NULL}
  31. };
  32. static TaggedString EMPTY = {LUA_T_STRING, {0}, {{NOT_USED, NOT_USED}}, 2, {0}};
  33. static unsigned long hash (char *s, int tag)
  34. {
  35. unsigned long h;
  36. if (tag != LUA_T_STRING)
  37. h = (unsigned long)s;
  38. else {
  39. h = 0;
  40. while (*s)
  41. h = ((h<<5)-h)^(unsigned char)*(s++);
  42. }
  43. return h;
  44. }
  45. static void grow (stringtable *tb)
  46. {
  47. int newsize = luaO_redimension(tb->size);
  48. TaggedString **newhash = luaM_newvector(newsize, TaggedString *);
  49. int i;
  50. for (i=0; i<newsize; i++)
  51. newhash[i] = NULL;
  52. /* rehash */
  53. tb->nuse = 0;
  54. for (i=0; i<tb->size; i++) {
  55. if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) {
  56. int h = tb->hash[i]->uu.hash%newsize;
  57. while (newhash[h])
  58. h = (h+1)%newsize;
  59. newhash[h] = tb->hash[i];
  60. tb->nuse++;
  61. }
  62. }
  63. luaM_free(tb->hash);
  64. tb->size = newsize;
  65. tb->hash = newhash;
  66. }
  67. static TaggedString *newone(char *buff, int tag, unsigned long h)
  68. {
  69. TaggedString *ts;
  70. if (tag == LUA_T_STRING) {
  71. ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+strlen(buff));
  72. strcpy(ts->str, buff);
  73. ts->u.s.varindex = ts->u.s.constindex = NOT_USED;
  74. ts->tag = LUA_T_STRING;
  75. }
  76. else {
  77. ts = (TaggedString *)luaM_malloc(sizeof(TaggedString));
  78. ts->u.v = buff;
  79. ts->tag = tag == LUA_ANYTAG ? 0 : tag;
  80. }
  81. ts->marked = 0;
  82. ts->uu.hash = h;
  83. return ts;
  84. }
  85. static TaggedString *insert (char *buff, int tag, stringtable *tb)
  86. {
  87. TaggedString *ts;
  88. unsigned long h = hash(buff, tag);
  89. int i;
  90. int j = -1;
  91. if ((long)tb->nuse*3 >= (long)tb->size*2)
  92. grow(tb);
  93. i = h%tb->size;
  94. while ((ts = tb->hash[i]) != NULL)
  95. {
  96. if (ts == &EMPTY)
  97. j = i;
  98. else if ((ts->tag == LUA_T_STRING) ?
  99. (tag == LUA_T_STRING && (strcmp(buff, ts->str) == 0)) :
  100. ((tag == ts->tag || tag == LUA_ANYTAG) && buff == ts->u.v))
  101. return ts;
  102. i = (i+1)%tb->size;
  103. }
  104. /* not found */
  105. ++luaO_nentities;
  106. if (j != -1) /* is there an EMPTY space? */
  107. i = j;
  108. else
  109. tb->nuse++;
  110. ts = tb->hash[i] = newone(buff, tag, h);
  111. return ts;
  112. }
  113. TaggedString *luaS_createudata (void *udata, int tag)
  114. {
  115. return insert(udata, tag, &string_root[(unsigned)udata%NUM_HASHS]);
  116. }
  117. TaggedString *luaS_new (char *str)
  118. {
  119. return insert(str, LUA_T_STRING, &string_root[(unsigned)str[0]%NUM_HASHS]);
  120. }
  121. TaggedString *luaS_newfixedstring (char *str)
  122. {
  123. TaggedString *ts = luaS_new(str);
  124. if (ts->marked == 0)
  125. ts->marked = 2; /* avoid GC */
  126. return ts;
  127. }
  128. void luaS_free (TaggedString *l)
  129. {
  130. while (l) {
  131. TaggedString *next = l->uu.next;
  132. luaM_free(l);
  133. l = next;
  134. }
  135. }
  136. /*
  137. ** Garbage collection function.
  138. */
  139. TaggedString *luaS_collector (void)
  140. {
  141. TaggedString *frees = NULL;
  142. int i;
  143. for (i=0; i<NUM_HASHS; i++) {
  144. stringtable *tb = &string_root[i];
  145. int j;
  146. for (j=0; j<tb->size; j++) {
  147. TaggedString *t = tb->hash[j];
  148. if (t == NULL) continue;
  149. if (t->marked == 1)
  150. t->marked = 0;
  151. else if (!t->marked) {
  152. t->uu.next = frees;
  153. frees = t;
  154. tb->hash[j] = &EMPTY;
  155. --luaO_nentities;
  156. }
  157. }
  158. }
  159. return frees;
  160. }