diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-01-04 11:37:29 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-01-04 11:37:29 -0200 |
commit | d7294c6de8e8e2e5d124cfc20ff2ad1a1c2a84f5 (patch) | |
tree | 4ec288f0f552a65cb5ceb2f80bb4386f8a9418a1 | |
parent | 63a752f961dc8b6ced4f398c7d4cafdfc2a6b9f0 (diff) | |
download | lua-d7294c6de8e8e2e5d124cfc20ff2ad1a1c2a84f5.tar.gz lua-d7294c6de8e8e2e5d124cfc20ff2ad1a1c2a84f5.tar.bz2 lua-d7294c6de8e8e2e5d124cfc20ff2ad1a1c2a84f5.zip |
double hashing for string tables.
-rw-r--r-- | lstring.c | 97 |
1 files changed, 40 insertions, 57 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.c,v 1.14 1998/07/27 17:06:17 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 1.15 1998/08/10 21:36:32 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 | */ |
@@ -25,8 +25,7 @@ static TaggedString EMPTY = {{NULL, 2}, 0L, 0, | |||
25 | {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; | 25 | {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; |
26 | 26 | ||
27 | 27 | ||
28 | void luaS_init (void) | 28 | void luaS_init (void) { |
29 | { | ||
30 | int i; | 29 | int i; |
31 | L->string_root = luaM_newvector(NUM_HASHS, stringtable); | 30 | L->string_root = luaM_newvector(NUM_HASHS, stringtable); |
32 | for (i=0; i<NUM_HASHS; i++) { | 31 | for (i=0; i<NUM_HASHS; i++) { |
@@ -37,8 +36,7 @@ void luaS_init (void) | |||
37 | } | 36 | } |
38 | 37 | ||
39 | 38 | ||
40 | static unsigned long hash_s (char *s, long l) | 39 | static unsigned long hash_s (char *s, long l) { |
41 | { | ||
42 | unsigned long h = 0; /* seed */ | 40 | unsigned long h = 0; /* seed */ |
43 | while (l--) | 41 | while (l--) |
44 | h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++)); | 42 | h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++)); |
@@ -53,13 +51,12 @@ static int newsize (stringtable *tb) { | |||
53 | for (i=0; i<size; i++) | 51 | for (i=0; i<size; i++) |
54 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) | 52 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) |
55 | realuse++; | 53 | realuse++; |
56 | return luaO_redimension((realuse+1)*2); /* +1 is the new element */ | 54 | return luaO_redimension((realuse+1)*2+6); /* +1 is the new element, +6 to |
55 | ensure minimum size of 8 (for double hashing) */ | ||
57 | } | 56 | } |
58 | 57 | ||
59 | 58 | ||
60 | static void grow (stringtable *tb) | 59 | static void grow (stringtable *tb) { |
61 | { | ||
62 | |||
63 | int ns = newsize(tb); | 60 | int ns = newsize(tb); |
64 | TaggedString **newhash = luaM_newvector(ns, TaggedString *); | 61 | TaggedString **newhash = luaM_newvector(ns, TaggedString *); |
65 | int i; | 62 | int i; |
@@ -69,10 +66,12 @@ static void grow (stringtable *tb) | |||
69 | tb->nuse = 0; | 66 | tb->nuse = 0; |
70 | for (i=0; i<tb->size; i++) { | 67 | for (i=0; i<tb->size; i++) { |
71 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { | 68 | if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { |
72 | int h = tb->hash[i]->hash%ns; | 69 | unsigned long h = tb->hash[i]->hash; |
73 | while (newhash[h]) | 70 | int h1 = h%ns; |
74 | h = (h+1)%ns; | 71 | int h2 = 8-(h&7); |
75 | newhash[h] = tb->hash[i]; | 72 | while (newhash[h1]) |
73 | h1 = (h1+h2)%ns; | ||
74 | newhash[h1] = tb->hash[i]; | ||
76 | tb->nuse++; | 75 | tb->nuse++; |
77 | } | 76 | } |
78 | } | 77 | } |
@@ -82,8 +81,7 @@ static void grow (stringtable *tb) | |||
82 | } | 81 | } |
83 | 82 | ||
84 | 83 | ||
85 | static TaggedString *newone_s (char *str, long l, unsigned long h) | 84 | static TaggedString *newone_s (char *str, long l, unsigned long h) { |
86 | { | ||
87 | TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); | 85 | TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); |
88 | memcpy(ts->str, str, l); | 86 | memcpy(ts->str, str, l); |
89 | ts->str[l] = 0; /* ending 0 */ | 87 | ts->str[l] = 0; /* ending 0 */ |
@@ -97,8 +95,7 @@ static TaggedString *newone_s (char *str, long l, unsigned long h) | |||
97 | return ts; | 95 | return ts; |
98 | } | 96 | } |
99 | 97 | ||
100 | static TaggedString *newone_u (char *buff, int tag, unsigned long h) | 98 | static TaggedString *newone_u (char *buff, int tag, unsigned long h) { |
101 | { | ||
102 | TaggedString *ts = luaM_new(TaggedString); | 99 | TaggedString *ts = luaM_new(TaggedString); |
103 | ts->u.d.v = buff; | 100 | ts->u.d.v = buff; |
104 | ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; | 101 | ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; |
@@ -110,82 +107,76 @@ static TaggedString *newone_u (char *buff, int tag, unsigned long h) | |||
110 | return ts; | 107 | return ts; |
111 | } | 108 | } |
112 | 109 | ||
113 | static TaggedString *insert_s (char *str, long l, stringtable *tb) | 110 | static TaggedString *insert_s (char *str, long l, stringtable *tb) { |
114 | { | ||
115 | TaggedString *ts; | 111 | TaggedString *ts; |
116 | unsigned long h = hash_s(str, l); | 112 | unsigned long h = hash_s(str, l); |
117 | int size = tb->size; | 113 | int size = tb->size; |
118 | int i; | ||
119 | int j = -1; | 114 | int j = -1; |
115 | int h1; | ||
116 | int h2 = 8-(h&7); /* for double hashing */ | ||
120 | if ((long)tb->nuse*3 >= (long)size*2) { | 117 | if ((long)tb->nuse*3 >= (long)size*2) { |
121 | grow(tb); | 118 | grow(tb); |
122 | size = tb->size; | 119 | size = tb->size; |
123 | } | 120 | } |
124 | for (i = h%size; (ts = tb->hash[i]) != NULL; ) { | 121 | for (h1 = h%size; (ts = tb->hash[h1]) != NULL; h1 = (h1+h2)%size) { |
125 | if (ts == &EMPTY) | 122 | if (ts == &EMPTY) |
126 | j = i; | 123 | j = h1; |
127 | else if (ts->constindex >= 0 && | 124 | else if (ts->constindex >= 0 && |
128 | ts->u.s.len == l && | 125 | ts->u.s.len == l && |
129 | (memcmp(str, ts->str, l) == 0)) | 126 | (memcmp(str, ts->str, l) == 0)) |
130 | return ts; | 127 | return ts; |
131 | if (++i == size) i=0; | ||
132 | } | 128 | } |
133 | /* not found */ | 129 | /* not found */ |
134 | if (j != -1) /* is there an EMPTY space? */ | 130 | if (j != -1) /* is there an EMPTY space? */ |
135 | i = j; | 131 | h1 = j; |
136 | else | 132 | else |
137 | tb->nuse++; | 133 | tb->nuse++; |
138 | ts = tb->hash[i] = newone_s(str, l, h); | 134 | ts = tb->hash[h1] = newone_s(str, l, h); |
139 | return ts; | 135 | return ts; |
140 | } | 136 | } |
141 | 137 | ||
142 | static TaggedString *insert_u (void *buff, int tag, stringtable *tb) | 138 | static TaggedString *insert_u (void *buff, int tag, stringtable *tb) { |
143 | { | ||
144 | TaggedString *ts; | 139 | TaggedString *ts; |
145 | unsigned long h = (unsigned long)buff; | 140 | unsigned long h = (unsigned long)buff; |
146 | int size = tb->size; | 141 | int size = tb->size; |
147 | int i; | ||
148 | int j = -1; | 142 | int j = -1; |
143 | int h1; | ||
144 | int h2 = 8-(h&7); /* for double hashing */ | ||
149 | if ((long)tb->nuse*3 >= (long)size*2) { | 145 | if ((long)tb->nuse*3 >= (long)size*2) { |
150 | grow(tb); | 146 | grow(tb); |
151 | size = tb->size; | 147 | size = tb->size; |
152 | } | 148 | } |
153 | for (i = h%size; (ts = tb->hash[i]) != NULL; ) { | 149 | for (h1 = h%size; (ts = tb->hash[h1]) != NULL; h1 = (h1+h2)%size) { |
154 | if (ts == &EMPTY) | 150 | if (ts == &EMPTY) |
155 | j = i; | 151 | j = h1; |
156 | else if (ts->constindex < 0 && /* is a udata? */ | 152 | else if (ts->constindex < 0 && /* is a udata? */ |
157 | (tag == ts->u.d.tag || tag == LUA_ANYTAG) && | 153 | (tag == ts->u.d.tag || tag == LUA_ANYTAG) && |
158 | buff == ts->u.d.v) | 154 | buff == ts->u.d.v) |
159 | return ts; | 155 | return ts; |
160 | if (++i == size) i=0; | ||
161 | } | 156 | } |
162 | /* not found */ | 157 | /* not found */ |
163 | if (j != -1) /* is there an EMPTY space? */ | 158 | if (j != -1) /* is there an EMPTY space? */ |
164 | i = j; | 159 | h1 = j; |
165 | else | 160 | else |
166 | tb->nuse++; | 161 | tb->nuse++; |
167 | ts = tb->hash[i] = newone_u(buff, tag, h); | 162 | ts = tb->hash[h1] = newone_u(buff, tag, h); |
168 | return ts; | 163 | return ts; |
169 | } | 164 | } |
170 | 165 | ||
171 | TaggedString *luaS_createudata (void *udata, int tag) | 166 | TaggedString *luaS_createudata (void *udata, int tag) { |
172 | { | ||
173 | return insert_u(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); | 167 | return insert_u(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); |
174 | } | 168 | } |
175 | 169 | ||
176 | TaggedString *luaS_newlstr (char *str, long l) | 170 | TaggedString *luaS_newlstr (char *str, long l) { |
177 | { | ||
178 | int i = (l==0)?0:(unsigned char)str[0]; | 171 | int i = (l==0)?0:(unsigned char)str[0]; |
179 | return insert_s(str, l, &L->string_root[i%NUM_HASHS]); | 172 | return insert_s(str, l, &L->string_root[i%NUM_HASHS]); |
180 | } | 173 | } |
181 | 174 | ||
182 | TaggedString *luaS_new (char *str) | 175 | TaggedString *luaS_new (char *str) { |
183 | { | ||
184 | return luaS_newlstr(str, strlen(str)); | 176 | return luaS_newlstr(str, strlen(str)); |
185 | } | 177 | } |
186 | 178 | ||
187 | TaggedString *luaS_newfixedstring (char *str) | 179 | TaggedString *luaS_newfixedstring (char *str) { |
188 | { | ||
189 | TaggedString *ts = luaS_new(str); | 180 | TaggedString *ts = luaS_new(str); |
190 | if (ts->head.marked == 0) | 181 | if (ts->head.marked == 0) |
191 | ts->head.marked = 2; /* avoid GC */ | 182 | ts->head.marked = 2; /* avoid GC */ |
@@ -193,8 +184,7 @@ TaggedString *luaS_newfixedstring (char *str) | |||
193 | } | 184 | } |
194 | 185 | ||
195 | 186 | ||
196 | void luaS_free (TaggedString *l) | 187 | void luaS_free (TaggedString *l) { |
197 | { | ||
198 | while (l) { | 188 | while (l) { |
199 | TaggedString *next = (TaggedString *)l->head.next; | 189 | TaggedString *next = (TaggedString *)l->head.next; |
200 | L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); | 190 | L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); |
@@ -208,8 +198,7 @@ void luaS_free (TaggedString *l) | |||
208 | ** Garbage collection functions. | 198 | ** Garbage collection functions. |
209 | */ | 199 | */ |
210 | 200 | ||
211 | static void remove_from_list (GCnode *l) | 201 | static void remove_from_list (GCnode *l) { |
212 | { | ||
213 | while (l) { | 202 | while (l) { |
214 | GCnode *next = l->next; | 203 | GCnode *next = l->next; |
215 | while (next && !next->marked) | 204 | while (next && !next->marked) |
@@ -219,8 +208,7 @@ static void remove_from_list (GCnode *l) | |||
219 | } | 208 | } |
220 | 209 | ||
221 | 210 | ||
222 | TaggedString *luaS_collector (void) | 211 | TaggedString *luaS_collector (void) { |
223 | { | ||
224 | TaggedString *frees = NULL; | 212 | TaggedString *frees = NULL; |
225 | int i; | 213 | int i; |
226 | remove_from_list(&(L->rootglobal)); | 214 | remove_from_list(&(L->rootglobal)); |
@@ -243,8 +231,7 @@ TaggedString *luaS_collector (void) | |||
243 | } | 231 | } |
244 | 232 | ||
245 | 233 | ||
246 | TaggedString *luaS_collectudata (void) | 234 | TaggedString *luaS_collectudata (void) { |
247 | { | ||
248 | TaggedString *frees = NULL; | 235 | TaggedString *frees = NULL; |
249 | int i; | 236 | int i; |
250 | L->rootglobal.next = NULL; /* empty list of globals */ | 237 | L->rootglobal.next = NULL; /* empty list of globals */ |
@@ -264,8 +251,7 @@ TaggedString *luaS_collectudata (void) | |||
264 | } | 251 | } |
265 | 252 | ||
266 | 253 | ||
267 | void luaS_freeall (void) | 254 | void luaS_freeall (void) { |
268 | { | ||
269 | int i; | 255 | int i; |
270 | for (i=0; i<NUM_HASHS; i++) { | 256 | for (i=0; i<NUM_HASHS; i++) { |
271 | stringtable *tb = &L->string_root[i]; | 257 | stringtable *tb = &L->string_root[i]; |
@@ -281,8 +267,7 @@ void luaS_freeall (void) | |||
281 | } | 267 | } |
282 | 268 | ||
283 | 269 | ||
284 | void luaS_rawsetglobal (TaggedString *ts, TObject *newval) | 270 | void luaS_rawsetglobal (TaggedString *ts, TObject *newval) { |
285 | { | ||
286 | ts->u.s.globalval = *newval; | 271 | ts->u.s.globalval = *newval; |
287 | if (ts->head.next == (GCnode *)ts) { /* is not in list? */ | 272 | if (ts->head.next == (GCnode *)ts) { /* is not in list? */ |
288 | ts->head.next = L->rootglobal.next; | 273 | ts->head.next = L->rootglobal.next; |
@@ -291,8 +276,7 @@ void luaS_rawsetglobal (TaggedString *ts, TObject *newval) | |||
291 | } | 276 | } |
292 | 277 | ||
293 | 278 | ||
294 | char *luaS_travsymbol (int (*fn)(TObject *)) | 279 | char *luaS_travsymbol (int (*fn)(TObject *)) { |
295 | { | ||
296 | TaggedString *g; | 280 | TaggedString *g; |
297 | for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) | 281 | for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) |
298 | if (fn(&g->u.s.globalval)) | 282 | if (fn(&g->u.s.globalval)) |
@@ -301,8 +285,7 @@ char *luaS_travsymbol (int (*fn)(TObject *)) | |||
301 | } | 285 | } |
302 | 286 | ||
303 | 287 | ||
304 | int luaS_globaldefined (char *name) | 288 | int luaS_globaldefined (char *name) { |
305 | { | ||
306 | TaggedString *ts = luaS_new(name); | 289 | TaggedString *ts = luaS_new(name); |
307 | return ts->u.s.globalval.ttype != LUA_T_NIL; | 290 | return ts->u.s.globalval.ttype != LUA_T_NIL; |
308 | } | 291 | } |