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 | } |
