diff options
-rw-r--r-- | lstring.c | 82 |
1 files changed, 49 insertions, 33 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.c,v 1.19 1999/02/26 15:49:53 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 1.20 1999/08/16 20:52:00 roberto Exp roberto $ |
3 | ** String table (keeps all strings handled by Lua) | 3 | ** String table (keeps all strings handled by Lua) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -27,13 +27,24 @@ static TaggedString EMPTY = {{NULL, 2}, 0L, 0, | |||
27 | {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; | 27 | {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; |
28 | 28 | ||
29 | 29 | ||
30 | |||
31 | /* | ||
32 | ** to avoid hash tables with size = 0 (cannot hash with size=0), all | ||
33 | ** hash tables are initialized with this `array'. Elements are never | ||
34 | ** written here, because this table (with size=1) must grow to get an | ||
35 | ** element, and before it grows we replace it for a `real' table. | ||
36 | ** | ||
37 | */ | ||
38 | static TaggedString *init_hash[1] = {NULL}; | ||
39 | |||
40 | |||
30 | void luaS_init (void) { | 41 | void luaS_init (void) { |
31 | int i; | 42 | int i; |
32 | L->string_root = luaM_newvector(NUM_HASHS, stringtable); | 43 | L->string_root = luaM_newvector(NUM_HASHS, stringtable); |
33 | for (i=0; i<NUM_HASHS; i++) { | 44 | for (i=0; i<NUM_HASHS; i++) { |
34 | L->string_root[i].size = 0; | 45 | L->string_root[i].size = 1; |
35 | L->string_root[i].nuse = 0; | 46 | L->string_root[i].nuse = 0; |
36 | L->string_root[i].hash = NULL; | 47 | L->string_root[i].hash = init_hash; |
37 | } | 48 | } |
38 | } | 49 | } |
39 | 50 | ||
@@ -45,15 +56,16 @@ static unsigned long hash_s (const char *s, long l) { | |||
45 | return h; | 56 | return h; |
46 | } | 57 | } |
47 | 58 | ||
59 | |||
48 | static int newsize (stringtable *tb) { | 60 | static int newsize (stringtable *tb) { |
49 | int size = tb->size; | ||
50 | int realuse = 0; | 61 | int realuse = 0; |
51 | int i; | 62 | int i; |
52 | /* count how many entries are really in use */ | 63 | /* count how many entries are really in use */ |
53 | for (i=0; i<size; i++) | 64 | for (i=0; i<tb->size; i++) { |
54 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) | 65 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) |
55 | realuse++; | 66 | realuse++; |
56 | return luaO_redimension((realuse+1)*2); /* +1 is the new element */ | 67 | } |
68 | return luaO_redimension(realuse*2); | ||
57 | } | 69 | } |
58 | 70 | ||
59 | 71 | ||
@@ -109,17 +121,28 @@ static TaggedString *newone_u (void *buff, int tag, unsigned long h) { | |||
109 | return ts; | 121 | return ts; |
110 | } | 122 | } |
111 | 123 | ||
124 | |||
125 | static void newentry (stringtable *tb, TaggedString *ts, int h1) { | ||
126 | tb->nuse++; | ||
127 | if ((long)tb->nuse*3 < (long)tb->size*2) /* still have room? */ | ||
128 | tb->hash[h1] = ts; | ||
129 | else { /* must grow */ | ||
130 | if (tb->hash == init_hash) { /* cannot change init_hash */ | ||
131 | LUA_ASSERT(h1==0, "`init_hash' has size 1"); | ||
132 | tb->hash = luaM_newvector(1, TaggedString *); /* so, `clone' it */ | ||
133 | } | ||
134 | tb->hash[h1] = ts; | ||
135 | grow(tb); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | |||
112 | static TaggedString *insert_s (const char *str, long l, stringtable *tb) { | 140 | static TaggedString *insert_s (const char *str, long l, stringtable *tb) { |
113 | TaggedString *ts; | 141 | TaggedString *ts; |
114 | unsigned long h = hash_s(str, l); | 142 | unsigned long h = hash_s(str, l); |
115 | int size = tb->size; | 143 | int size = tb->size; |
116 | int j = -1; | 144 | int j = -1; /* last empty place found (or -1) */ |
117 | int h1; | 145 | int h1 = h%size; |
118 | if ((long)tb->nuse*3 >= (long)size*2) { | ||
119 | grow(tb); | ||
120 | size = tb->size; | ||
121 | } | ||
122 | h1 = h%size; | ||
123 | while ((ts = tb->hash[h1]) != NULL) { | 146 | while ((ts = tb->hash[h1]) != NULL) { |
124 | if (ts == &EMPTY) | 147 | if (ts == &EMPTY) |
125 | j = h1; | 148 | j = h1; |
@@ -129,11 +152,11 @@ static TaggedString *insert_s (const char *str, long l, stringtable *tb) { | |||
129 | if (h1 >= size) h1 -= size; | 152 | if (h1 >= size) h1 -= size; |
130 | } | 153 | } |
131 | /* not found */ | 154 | /* not found */ |
155 | ts = newone_s(str, l, h); /* create new entry */ | ||
132 | if (j != -1) /* is there an EMPTY space? */ | 156 | if (j != -1) /* is there an EMPTY space? */ |
133 | h1 = j; | 157 | tb->hash[j] = ts; /* use it for new element */ |
134 | else | 158 | else |
135 | tb->nuse++; | 159 | newentry(tb, ts, h1); /* no EMPTY places; must use a virgin one */ |
136 | ts = tb->hash[h1] = newone_s(str, l, h); | ||
137 | return ts; | 160 | return ts; |
138 | } | 161 | } |
139 | 162 | ||
@@ -143,37 +166,31 @@ static TaggedString *insert_u (void *buff, int tag, stringtable *tb) { | |||
143 | unsigned long h = (unsigned long)buff; | 166 | unsigned long h = (unsigned long)buff; |
144 | int size = tb->size; | 167 | int size = tb->size; |
145 | int j = -1; | 168 | int j = -1; |
146 | int h1; | 169 | int h1 = h%size; |
147 | if ((long)tb->nuse*3 >= (long)size*2) { | ||
148 | grow(tb); | ||
149 | size = tb->size; | ||
150 | } | ||
151 | h1 = h%size; | ||
152 | while ((ts = tb->hash[h1]) != NULL) { | 170 | while ((ts = tb->hash[h1]) != NULL) { |
153 | if (ts == &EMPTY) | 171 | if (ts == &EMPTY) |
154 | j = h1; | 172 | j = h1; |
155 | else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v) | 173 | else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v) |
156 | return ts; | 174 | return ts; |
157 | h1 += (h&(size-2)) + 1; /* double hashing */ | 175 | h1 += (h&(size-2)) + 1; |
158 | if (h1 >= size) h1 -= size; | 176 | if (h1 >= size) h1 -= size; |
159 | } | 177 | } |
160 | /* not found */ | 178 | ts = newone_u(buff, tag, h); |
161 | if (j != -1) /* is there an EMPTY space? */ | 179 | if (j != -1) |
162 | h1 = j; | 180 | tb->hash[j] = ts; |
163 | else | 181 | else |
164 | tb->nuse++; | 182 | newentry(tb, ts, h1); |
165 | ts = tb->hash[h1] = newone_u(buff, tag, h); | ||
166 | return ts; | 183 | return ts; |
167 | } | 184 | } |
168 | 185 | ||
169 | 186 | ||
170 | TaggedString *luaS_createudata (void *udata, int tag) { | 187 | TaggedString *luaS_createudata (void *udata, int tag) { |
171 | int t = ((unsigned)udata%NUM_HASHUDATA)+NUM_HASHSTR; | 188 | int t = ((unsigned int)udata%NUM_HASHUDATA)+NUM_HASHSTR; |
172 | return insert_u(udata, tag, &L->string_root[t]); | 189 | return insert_u(udata, tag, &L->string_root[t]); |
173 | } | 190 | } |
174 | 191 | ||
175 | TaggedString *luaS_newlstr (const char *str, long l) { | 192 | TaggedString *luaS_newlstr (const char *str, long l) { |
176 | int t = (l==0) ? 0 : ((int)((unsigned char)str[0]*l))%NUM_HASHSTR; | 193 | int t = (l==0) ? 0 : ((int)((unsigned char)str[0]+l))%NUM_HASHSTR; |
177 | return insert_s(str, l, &L->string_root[t]); | 194 | return insert_s(str, l, &L->string_root[t]); |
178 | } | 195 | } |
179 | 196 | ||
@@ -264,10 +281,9 @@ void luaS_freeall (void) { | |||
264 | int j; | 281 | int j; |
265 | for (j=0; j<tb->size; j++) { | 282 | for (j=0; j<tb->size; j++) { |
266 | TaggedString *t = tb->hash[j]; | 283 | TaggedString *t = tb->hash[j]; |
267 | if (t == &EMPTY) continue; | 284 | if (t != &EMPTY) luaM_free(t); |
268 | luaM_free(t); | ||
269 | } | 285 | } |
270 | luaM_free(tb->hash); | 286 | if (tb->hash != init_hash) luaM_free(tb->hash); |
271 | } | 287 | } |
272 | luaM_free(L->string_root); | 288 | luaM_free(L->string_root); |
273 | } | 289 | } |