diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-10-14 17:13:31 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1999-10-14 17:13:31 -0200 |
commit | 4e9f2d13d5b6fa71ca480394e0b7e75463d4aeec (patch) | |
tree | d11eee681ce7b01a273e489f47e070494b51de1a | |
parent | b6ebbb2fee13aa223fdd12921cd0411e02db9dd0 (diff) | |
download | lua-4e9f2d13d5b6fa71ca480394e0b7e75463d4aeec.tar.gz lua-4e9f2d13d5b6fa71ca480394e0b7e75463d4aeec.tar.bz2 lua-4e9f2d13d5b6fa71ca480394e0b7e75463d4aeec.zip |
new implementation of hash tables.
-rw-r--r-- | lapi.c | 6 | ||||
-rw-r--r-- | lbuiltin.c | 73 | ||||
-rw-r--r-- | lgc.c | 19 | ||||
-rw-r--r-- | lobject.h | 15 | ||||
-rw-r--r-- | lstring.c | 9 | ||||
-rw-r--r-- | lstring.h | 4 | ||||
-rw-r--r-- | ltable.c | 271 | ||||
-rw-r--r-- | ltable.h | 15 | ||||
-rw-r--r-- | lvm.c | 4 |
9 files changed, 287 insertions, 129 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lapi.c,v 1.52 1999/10/07 19:04:30 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 1.53 1999/10/11 16:13:11 roberto Exp roberto $ |
3 | ** Lua API | 3 | ** Lua API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -422,11 +422,11 @@ const char *lua_nextvar (const char *varname) { | |||
422 | 422 | ||
423 | 423 | ||
424 | int luaA_next (const Hash *t, int i) { | 424 | int luaA_next (const Hash *t, int i) { |
425 | int tsize = nhash(t); | 425 | int tsize = t->size; |
426 | for (; i<tsize; i++) { | 426 | for (; i<tsize; i++) { |
427 | Node *n = node(t, i); | 427 | Node *n = node(t, i); |
428 | if (ttype(val(n)) != LUA_T_NIL) { | 428 | if (ttype(val(n)) != LUA_T_NIL) { |
429 | luaA_pushobject(ref(n)); | 429 | luaA_pushobject(key(n)); |
430 | luaA_pushobject(val(n)); | 430 | luaA_pushobject(val(n)); |
431 | return i+1; /* index to be used next time */ | 431 | return i+1; /* index to be used next time */ |
432 | } | 432 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lbuiltin.c,v 1.65 1999/10/07 19:04:30 roberto Exp roberto $ | 2 | ** $Id: lbuiltin.c,v 1.66 1999/10/11 16:13:11 roberto Exp roberto $ |
3 | ** Built-in functions | 3 | ** Built-in functions |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -44,13 +44,13 @@ static void pushtagstring (TaggedString *s) { | |||
44 | 44 | ||
45 | static real getsize (const Hash *h) { | 45 | static real getsize (const Hash *h) { |
46 | real max = 0; | 46 | real max = 0; |
47 | int i = nhash(h); | 47 | int i = h->size; |
48 | Node *n = h->node; | 48 | Node *n = h->node; |
49 | while (i--) { | 49 | while (i--) { |
50 | if (ttype(ref(n)) == LUA_T_NUMBER && | 50 | if (ttype(key(n)) == LUA_T_NUMBER && |
51 | ttype(val(n)) != LUA_T_NIL && | 51 | ttype(val(n)) != LUA_T_NIL && |
52 | nvalue(ref(n)) > max) | 52 | nvalue(key(n)) > max) |
53 | max = nvalue(ref(n)); | 53 | max = nvalue(key(n)); |
54 | n++; | 54 | n++; |
55 | } | 55 | } |
56 | return max; | 56 | return max; |
@@ -59,7 +59,7 @@ static real getsize (const Hash *h) { | |||
59 | 59 | ||
60 | static real getnarg (const Hash *a) { | 60 | static real getnarg (const Hash *a) { |
61 | TObject index; | 61 | TObject index; |
62 | TObject *value; | 62 | const TObject *value; |
63 | /* value = table.n */ | 63 | /* value = table.n */ |
64 | ttype(&index) = LUA_T_STRING; | 64 | ttype(&index) = LUA_T_STRING; |
65 | tsvalue(&index) = luaS_new("n"); | 65 | tsvalue(&index) = luaS_new("n"); |
@@ -337,7 +337,13 @@ static void luaB_nextvar (void) { | |||
337 | static void luaB_next (void) { | 337 | static void luaB_next (void) { |
338 | const Hash *a = gethash(1); | 338 | const Hash *a = gethash(1); |
339 | const TObject *k = luaA_Address(luaL_nonnullarg(2)); | 339 | const TObject *k = luaA_Address(luaL_nonnullarg(2)); |
340 | int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1; | 340 | int i; /* will get first element after `i' */ |
341 | if (ttype(k) == LUA_T_NIL) | ||
342 | i = 0; /* get first */ | ||
343 | else { | ||
344 | i = luaH_pos(a, k)+1; | ||
345 | luaL_arg_check(i != 0, 2, "key not found"); | ||
346 | } | ||
341 | if (luaA_next(a, i) == 0) | 347 | if (luaA_next(a, i) == 0) |
342 | lua_pushnil(); | 348 | lua_pushnil(); |
343 | } | 349 | } |
@@ -408,7 +414,7 @@ static void luaB_foreachi (void) { | |||
408 | stack may be reallocated by the call. Moreover, some C compilers do not | 414 | stack may be reallocated by the call. Moreover, some C compilers do not |
409 | initialize structs, so we must do the assignment after the declaration */ | 415 | initialize structs, so we must do the assignment after the declaration */ |
410 | f = *luaA_Address(luaL_functionarg(2)); | 416 | f = *luaA_Address(luaL_functionarg(2)); |
411 | luaD_checkstack(3); /* for f, ref, and val */ | 417 | luaD_checkstack(3); /* for f, key, and val */ |
412 | for (i=1; i<=n; i++) { | 418 | for (i=1; i<=n; i++) { |
413 | *(L->stack.top++) = f; | 419 | *(L->stack.top++) = f; |
414 | ttype(L->stack.top) = LUA_T_NUMBER; nvalue(L->stack.top++) = i; | 420 | ttype(L->stack.top) = LUA_T_NUMBER; nvalue(L->stack.top++) = i; |
@@ -426,12 +432,12 @@ static void luaB_foreach (void) { | |||
426 | int i; | 432 | int i; |
427 | TObject f; /* see comment in 'foreachi' */ | 433 | TObject f; /* see comment in 'foreachi' */ |
428 | f = *luaA_Address(luaL_functionarg(2)); | 434 | f = *luaA_Address(luaL_functionarg(2)); |
429 | luaD_checkstack(3); /* for f, ref, and val */ | 435 | luaD_checkstack(3); /* for f, key, and val */ |
430 | for (i=0; i<a->nhash; i++) { | 436 | for (i=0; i<a->size; i++) { |
431 | const Node *nd = &(a->node[i]); | 437 | const Node *nd = &(a->node[i]); |
432 | if (ttype(val(nd)) != LUA_T_NIL) { | 438 | if (ttype(val(nd)) != LUA_T_NIL) { |
433 | *(L->stack.top++) = f; | 439 | *(L->stack.top++) = f; |
434 | *(L->stack.top++) = *ref(nd); | 440 | *(L->stack.top++) = *key(nd); |
435 | *(L->stack.top++) = *val(nd); | 441 | *(L->stack.top++) = *val(nd); |
436 | luaD_calln(2, 1); | 442 | luaD_calln(2, 1); |
437 | if (ttype(L->stack.top-1) != LUA_T_NIL) | 443 | if (ttype(L->stack.top-1) != LUA_T_NIL) |
@@ -531,36 +537,37 @@ static int sort_comp (lua_Object f, const TObject *a, const TObject *b) { | |||
531 | } | 537 | } |
532 | 538 | ||
533 | static void auxsort (Hash *a, int l, int u, lua_Object f) { | 539 | static void auxsort (Hash *a, int l, int u, lua_Object f) { |
540 | StkId P = L->stack.top - L->stack.stack; /* temporary place for pivot */ | ||
541 | L->stack.top++; | ||
542 | ttype(L->stack.stack+P) = LUA_T_NIL; | ||
534 | while (l < u) { /* for tail recursion */ | 543 | while (l < u) { /* for tail recursion */ |
535 | TObject *P; | ||
536 | int i, j; | 544 | int i, j; |
537 | /* sort elements a[l], a[(l+u)/2] and a[u] */ | 545 | /* sort elements a[l], a[(l+u)/2] and a[u] */ |
538 | if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[l]>a[u]? */ | 546 | if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[u]<a[l]? */ |
539 | swap(a, l, u); | 547 | swap(a, l, u); |
540 | if (u-l == 1) break; /* only 2 elements */ | 548 | if (u-l == 1) break; /* only 2 elements */ |
541 | i = (l+u)/2; | 549 | i = (l+u)/2; |
542 | P = luaH_getint(a, i); | 550 | *(L->stack.stack+P) = *luaH_getint(a, i); /* P = a[i] */ |
543 | if (sort_comp(f, P, luaH_getint(a, l))) /* a[l]>a[i]? */ | 551 | if (sort_comp(f, L->stack.stack+P, luaH_getint(a, l))) /* a[i]<a[l]? */ |
544 | swap(a, l, i); | 552 | swap(a, l, i); |
545 | else if (sort_comp(f, luaH_getint(a, u), P)) /* a[i]>a[u]? */ | 553 | else if (sort_comp(f, luaH_getint(a, u), L->stack.stack+P)) /* a[u]<a[i]? */ |
546 | swap(a, i, u); | 554 | swap(a, i, u); |
547 | if (u-l == 2) break; /* only 3 elements */ | 555 | if (u-l == 2) break; /* only 3 elements */ |
548 | P = L->stack.top++; | 556 | *(L->stack.stack+P) = *luaH_getint(a, i); /* save pivot on stack (for GC) */ |
549 | *P = *luaH_getint(a, i); /* save pivot on stack (for GC) */ | ||
550 | swap(a, i, u-1); /* put median element as pivot (a[u-1]) */ | 557 | swap(a, i, u-1); /* put median element as pivot (a[u-1]) */ |
551 | /* a[l] <= P == a[u-1] <= a[u], only needs to sort from l+1 to u-2 */ | 558 | /* a[l] <= P == a[u-1] <= a[u], only needs to sort from l+1 to u-2 */ |
552 | i = l; j = u-1; | 559 | i = l; j = u-1; |
553 | for (;;) { | 560 | for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ |
554 | /* invariant: a[l..i] <= P <= a[j..u] */ | 561 | /* repeat i++ until a[i] >= P */ |
555 | while (sort_comp(f, luaH_getint(a, ++i), P)) /* stop when a[i] >= P */ | 562 | while (sort_comp(f, luaH_getint(a, ++i), L->stack.stack+P)) |
556 | if (i>u) lua_error("invalid order function for sorting"); | 563 | if (i>u) lua_error("invalid order function for sorting"); |
557 | while (sort_comp(f, P, luaH_getint(a, --j))) /* stop when a[j] <= P */ | 564 | /* repeat j-- until a[j] <= P */ |
565 | while (sort_comp(f, (L->stack.stack+P), luaH_getint(a, --j))) | ||
558 | if (j<l) lua_error("invalid order function for sorting"); | 566 | if (j<l) lua_error("invalid order function for sorting"); |
559 | if (j<i) break; | 567 | if (j<i) break; |
560 | swap(a, i, j); | 568 | swap(a, i, j); |
561 | } | 569 | } |
562 | swap(a, u-1, i); /* swap pivot (a[u-1]) with a[i] */ | 570 | swap(a, u-1, i); /* swap pivot (a[u-1]) with a[i] */ |
563 | L->stack.top--; /* remove pivot from stack */ | ||
564 | /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ | 571 | /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ |
565 | /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */ | 572 | /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */ |
566 | if (i-l < u-i) { | 573 | if (i-l < u-i) { |
@@ -571,6 +578,7 @@ static void auxsort (Hash *a, int l, int u, lua_Object f) { | |||
571 | } | 578 | } |
572 | auxsort(a, j, i, f); /* call recursively the smaller one */ | 579 | auxsort(a, j, i, f); /* call recursively the smaller one */ |
573 | } /* repeat the routine for the larger one */ | 580 | } /* repeat the routine for the larger one */ |
581 | L->stack.top--; /* remove pivot from stack */ | ||
574 | } | 582 | } |
575 | 583 | ||
576 | static void luaB_sort (void) { | 584 | static void luaB_sort (void) { |
@@ -608,7 +616,23 @@ static void mem_query (void) { | |||
608 | 616 | ||
609 | static void hash_query (void) { | 617 | static void hash_query (void) { |
610 | const TObject *o = luaA_Address(luaL_nonnullarg(1)); | 618 | const TObject *o = luaA_Address(luaL_nonnullarg(1)); |
611 | lua_pushnumber(luaH_hashindex(o)); | 619 | luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "string expected"); |
620 | lua_pushnumber(tsvalue(o)->hash); | ||
621 | } | ||
622 | |||
623 | |||
624 | static void table_query (void) { | ||
625 | const Hash *t = avalue(luaA_Address(luaL_tablearg(1))); | ||
626 | int i = luaL_opt_int(2, -1); | ||
627 | if (i == -1) { | ||
628 | lua_pushnumber(t->size); | ||
629 | lua_pushnumber(t->firstfree - t->node); | ||
630 | } | ||
631 | else if (i < t->size) { | ||
632 | luaA_pushobject(&t->node[i].key); | ||
633 | luaA_pushobject(&t->node[i].val); | ||
634 | lua_pushnumber(t->node[i].next == NULL ? 0 : t->node[i].next - t->node); | ||
635 | } | ||
612 | } | 636 | } |
613 | 637 | ||
614 | 638 | ||
@@ -715,6 +739,7 @@ static const struct luaL_reg builtin_funcs[] = { | |||
715 | {"extra", extra_services}, | 739 | {"extra", extra_services}, |
716 | {"hash", hash_query}, | 740 | {"hash", hash_query}, |
717 | {"querystr", query_strings}, | 741 | {"querystr", query_strings}, |
742 | {"querytab", table_query}, | ||
718 | {"testC", testC}, | 743 | {"testC", testC}, |
719 | {"totalmem", mem_query}, | 744 | {"totalmem", mem_query}, |
720 | #endif | 745 | #endif |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.27 1999/10/04 17:51:04 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.28 1999/10/11 16:13:11 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -51,10 +51,10 @@ static void hashmark (Hash *h) { | |||
51 | if (!h->marked) { | 51 | if (!h->marked) { |
52 | int i; | 52 | int i; |
53 | h->marked = 1; | 53 | h->marked = 1; |
54 | for (i=nhash(h)-1; i>=0; i--) { | 54 | for (i=h->size-1; i>=0; i--) { |
55 | Node *n = node(h,i); | 55 | Node *n = node(h,i); |
56 | if (ttype(ref(n)) != LUA_T_NIL) { | 56 | if (ttype(key(n)) != LUA_T_NIL) { |
57 | markobject(&n->ref); | 57 | markobject(&n->key); |
58 | markobject(&n->val); | 58 | markobject(&n->val); |
59 | } | 59 | } |
60 | } | 60 | } |
@@ -157,11 +157,11 @@ static void collecttable (void) { | |||
157 | } | 157 | } |
158 | 158 | ||
159 | 159 | ||
160 | static void clear_global_list (void) { | 160 | static void clear_global_list (int limit) { |
161 | TaggedString **p = &L->rootglobal; | 161 | TaggedString **p = &L->rootglobal; |
162 | TaggedString *next; | 162 | TaggedString *next; |
163 | while ((next = *p) != NULL) { | 163 | while ((next = *p) != NULL) { |
164 | if (next->marked) p = &next->nextglobal; | 164 | if (next->marked >= limit) p = &next->nextglobal; |
165 | else *p = next->nextglobal; | 165 | else *p = next->nextglobal; |
166 | } | 166 | } |
167 | } | 167 | } |
@@ -176,7 +176,7 @@ static void collectstring (int limit) { | |||
176 | TObject o; /* to call userdata 'gc' tag method */ | 176 | TObject o; /* to call userdata 'gc' tag method */ |
177 | int i; | 177 | int i; |
178 | ttype(&o) = LUA_T_USERDATA; | 178 | ttype(&o) = LUA_T_USERDATA; |
179 | clear_global_list(); | 179 | clear_global_list(limit); |
180 | for (i=0; i<NUM_HASHS; i++) { /* for each hash table */ | 180 | for (i=0; i<NUM_HASHS; i++) { /* for each hash table */ |
181 | stringtable *tb = &L->string_root[i]; | 181 | stringtable *tb = &L->string_root[i]; |
182 | int j; | 182 | int j; |
@@ -200,6 +200,8 @@ static void collectstring (int limit) { | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | } | 202 | } |
203 | if ((tb->nuse+1)*6 < tb->size) | ||
204 | luaS_grow(tb); /* table is too big; `grow' it to a smaller size */ | ||
203 | } | 205 | } |
204 | } | 206 | } |
205 | 207 | ||
@@ -237,7 +239,8 @@ void luaC_collect (int all) { | |||
237 | collectstring(all?MAX_INT:1); | 239 | collectstring(all?MAX_INT:1); |
238 | collectproto(); | 240 | collectproto(); |
239 | collectclosure(); | 241 | collectclosure(); |
240 | luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ | 242 | if (!all) |
243 | luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ | ||
241 | } | 244 | } |
242 | 245 | ||
243 | 246 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 1.31 1999/10/04 17:51:04 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 1.32 1999/10/11 16:13:11 roberto Exp roberto $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -162,27 +162,30 @@ typedef struct Closure { | |||
162 | 162 | ||
163 | 163 | ||
164 | typedef struct node { | 164 | typedef struct node { |
165 | TObject ref; | 165 | TObject key; |
166 | TObject val; | 166 | TObject val; |
167 | struct node *next; /* for chaining */ | ||
167 | } Node; | 168 | } Node; |
168 | 169 | ||
169 | typedef struct Hash { | 170 | typedef struct Hash { |
171 | int htag; | ||
172 | Node *node; | ||
173 | unsigned int size; | ||
174 | Node *firstfree; /* this position is free; all positions after it are full */ | ||
170 | struct Hash *next; | 175 | struct Hash *next; |
171 | int marked; | 176 | int marked; |
172 | Node *node; | ||
173 | int nhash; | ||
174 | int nuse; | ||
175 | int htag; | ||
176 | } Hash; | 177 | } Hash; |
177 | 178 | ||
178 | 179 | ||
179 | extern const char *const luaO_typenames[]; | 180 | extern const char *const luaO_typenames[]; |
180 | 181 | ||
182 | |||
181 | #define luaO_typename(o) luaO_typenames[-ttype(o)] | 183 | #define luaO_typename(o) luaO_typenames[-ttype(o)] |
182 | 184 | ||
183 | 185 | ||
184 | extern const TObject luaO_nilobject; | 186 | extern const TObject luaO_nilobject; |
185 | 187 | ||
188 | |||
186 | #define luaO_equalObj(t1,t2) ((ttype(t1) != ttype(t2)) ? 0 \ | 189 | #define luaO_equalObj(t1,t2) ((ttype(t1) != ttype(t2)) ? 0 \ |
187 | : luaO_equalval(t1,t2)) | 190 | : luaO_equalval(t1,t2)) |
188 | int luaO_equalval (const TObject *t1, const TObject *t2); | 191 | int luaO_equalval (const TObject *t1, const TObject *t2); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.c,v 1.22 1999/10/04 17:51:04 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 1.23 1999/10/11 16:13:11 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 | */ |
@@ -48,6 +48,7 @@ void luaS_freeall (void) { | |||
48 | luaM_free(L->string_root[i].hash); | 48 | luaM_free(L->string_root[i].hash); |
49 | } | 49 | } |
50 | luaM_free(L->string_root); | 50 | luaM_free(L->string_root); |
51 | LUA_ASSERT(init_hash[0] == NULL, "init_hash corrupted"); | ||
51 | } | 52 | } |
52 | 53 | ||
53 | 54 | ||
@@ -59,8 +60,8 @@ static unsigned long hash_s (const char *s, long l) { | |||
59 | } | 60 | } |
60 | 61 | ||
61 | 62 | ||
62 | static void grow (stringtable *tb) { | 63 | void luaS_grow (stringtable *tb) { |
63 | int ns = luaO_redimension(tb->size*2); /* new size */ | 64 | int ns = luaO_redimension(tb->nuse*2); /* new size */ |
64 | TaggedString **newhash = luaM_newvector(ns, TaggedString *); | 65 | TaggedString **newhash = luaM_newvector(ns, TaggedString *); |
65 | int i; | 66 | int i; |
66 | for (i=0; i<ns; i++) newhash[i] = NULL; | 67 | for (i=0; i<ns; i++) newhash[i] = NULL; |
@@ -122,7 +123,7 @@ static void newentry (stringtable *tb, TaggedString *ts, int h) { | |||
122 | tb->hash = luaM_newvector(1, TaggedString *); /* so, `clone' it */ | 123 | tb->hash = luaM_newvector(1, TaggedString *); /* so, `clone' it */ |
123 | tb->hash[0] = NULL; | 124 | tb->hash[0] = NULL; |
124 | } | 125 | } |
125 | grow(tb); | 126 | luaS_grow(tb); |
126 | h = ts->hash%tb->size; /* new hash position */ | 127 | h = ts->hash%tb->size; /* new hash position */ |
127 | } | 128 | } |
128 | ts->nexthash = tb->hash[h]; /* chain new entry */ | 129 | ts->nexthash = tb->hash[h]; /* chain new entry */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.h,v 1.9 1999/10/04 17:51:04 roberto Exp roberto $ | 2 | ** $Id: lstring.h,v 1.10 1999/10/11 16:13:11 roberto Exp roberto $ |
3 | ** String table (keep all strings handled by Lua) | 3 | ** String table (keep all strings handled by Lua) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | 10 | ||
11 | #include "lobject.h" | 11 | #include "lobject.h" |
12 | #include "lstate.h" | ||
12 | 13 | ||
13 | 14 | ||
14 | #define NUM_HASHSTR 31 /* a prime not in array `dimensions' */ | 15 | #define NUM_HASHSTR 31 /* a prime not in array `dimensions' */ |
@@ -25,6 +26,7 @@ | |||
25 | 26 | ||
26 | 27 | ||
27 | void luaS_init (void); | 28 | void luaS_init (void); |
29 | void luaS_grow (stringtable *tb); | ||
28 | TaggedString *luaS_createudata (void *udata, int tag); | 30 | TaggedString *luaS_createudata (void *udata, int tag); |
29 | void luaS_freeall (void); | 31 | void luaS_freeall (void); |
30 | void luaS_free (TaggedString *ts); | 32 | void luaS_free (TaggedString *ts); |
@@ -1,10 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 1.24 1999/09/22 14:38:45 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 1.25 1999/10/04 17:51:04 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
6 | 6 | ||
7 | 7 | ||
8 | /* | ||
9 | ** Implementation of tables (aka arrays, objects, or hash tables); | ||
10 | ** uses a mix of chained scatter table with Brent's variation. | ||
11 | ** A main invariant of these tables is that, if an element is not | ||
12 | ** in its main position (i.e. the `original' position that its hash gives | ||
13 | ** to it), then the colliding element is in its own main position. | ||
14 | ** In other words, there are collisions only when two elements have the | ||
15 | ** same main position (i.e. the same hash values for that table size). | ||
16 | ** Because of that, the load factor of these tables can be 100% without | ||
17 | ** performance penalties. | ||
18 | */ | ||
19 | |||
20 | |||
8 | #include "lauxlib.h" | 21 | #include "lauxlib.h" |
9 | #include "lmem.h" | 22 | #include "lmem.h" |
10 | #include "lobject.h" | 23 | #include "lobject.h" |
@@ -15,93 +28,104 @@ | |||
15 | 28 | ||
16 | #define gcsize(n) (1+(n/16)) | 29 | #define gcsize(n) (1+(n/16)) |
17 | 30 | ||
18 | #define nuse(t) ((t)->nuse) | ||
19 | #define nodevector(t) ((t)->node) | ||
20 | 31 | ||
21 | 32 | ||
22 | #define TagDefault LUA_T_ARRAY; | 33 | #define TagDefault LUA_T_ARRAY; |
23 | 34 | ||
24 | 35 | ||
25 | 36 | ||
26 | static long int hashindex (const TObject *ref) { | 37 | /* |
27 | long int h; | 38 | ** returns the `main' position of an element in a table (that is, the index |
28 | switch (ttype(ref)) { | 39 | ** of its hash value) |
40 | */ | ||
41 | static Node *luaH_mainposition (const Hash *t, const TObject *key) { | ||
42 | unsigned long h; | ||
43 | switch (ttype(key)) { | ||
29 | case LUA_T_NUMBER: | 44 | case LUA_T_NUMBER: |
30 | h = (long int)nvalue(ref); | 45 | h = (unsigned long)(long)nvalue(key); |
31 | break; | 46 | break; |
32 | case LUA_T_STRING: case LUA_T_USERDATA: | 47 | case LUA_T_STRING: case LUA_T_USERDATA: |
33 | h = (IntPoint)tsvalue(ref); | 48 | h = tsvalue(key)->hash; |
34 | break; | 49 | break; |
35 | case LUA_T_ARRAY: | 50 | case LUA_T_ARRAY: |
36 | h = (IntPoint)avalue(ref); | 51 | h = (IntPoint)avalue(key); |
37 | break; | 52 | break; |
38 | case LUA_T_PROTO: | 53 | case LUA_T_PROTO: |
39 | h = (IntPoint)tfvalue(ref); | 54 | h = (IntPoint)tfvalue(key); |
40 | break; | 55 | break; |
41 | case LUA_T_CPROTO: | 56 | case LUA_T_CPROTO: |
42 | h = (IntPoint)fvalue(ref); | 57 | h = (IntPoint)fvalue(key); |
43 | break; | 58 | break; |
44 | case LUA_T_CLOSURE: | 59 | case LUA_T_CLOSURE: |
45 | h = (IntPoint)clvalue(ref); | 60 | h = (IntPoint)clvalue(key); |
46 | break; | 61 | break; |
47 | default: | 62 | default: |
48 | lua_error("unexpected type to index table"); | 63 | lua_error("unexpected type to index table"); |
49 | h = 0; /* to avoid warnings */ | 64 | h = 0; /* to avoid warnings */ |
50 | } | 65 | } |
51 | return (h >= 0 ? h : -(h+1)); | 66 | return &t->node[h%t->size]; |
52 | } | 67 | } |
53 | 68 | ||
54 | 69 | ||
55 | Node *luaH_present (const Hash *t, const TObject *key) { | 70 | const TObject *luaH_get (const Hash *t, const TObject *key) { |
56 | const int tsize = nhash(t); | 71 | Node *n = luaH_mainposition(t, key); |
57 | const long int h = hashindex(key); | 72 | do { |
58 | int h1 = h%tsize; | 73 | if (luaO_equalObj(key, &n->key)) |
59 | Node *n = node(t, h1); | 74 | return &n->val; |
60 | /* keep looking until an entry with "ref" equal to key or nil */ | 75 | n = n->next; |
61 | while ((ttype(ref(n)) == ttype(key)) ? !luaO_equalval(key, ref(n)) | 76 | } while (n); |
62 | : ttype(ref(n)) != LUA_T_NIL) { | 77 | return &luaO_nilobject; |
63 | h1 += (h&(tsize-2)) + 1; /* double hashing */ | 78 | } |
64 | if (h1 >= tsize) h1 -= tsize; | 79 | |
65 | n = node(t, h1); | 80 | |
66 | } | 81 | int luaH_pos (const Hash *t, const TObject *key) { |
67 | return n; | 82 | const TObject *v = luaH_get(t, key); |
83 | return (v == &luaO_nilobject) ? -1 : /* key not found */ | ||
84 | ((const char *)v - (const char *)(&t->node[0].val))/sizeof(Node); | ||
68 | } | 85 | } |
69 | 86 | ||
70 | 87 | ||
88 | |||
71 | static Node *hashnodecreate (int nhash) { | 89 | static Node *hashnodecreate (int nhash) { |
72 | Node *const v = luaM_newvector(nhash, Node); | 90 | Node *v = luaM_newvector(nhash, Node); |
73 | int i; | 91 | int i; |
74 | for (i=0; i<nhash; i++) | 92 | for (i=0; i<nhash; i++) { |
75 | ttype(ref(&v[i])) = ttype(val(&v[i])) = LUA_T_NIL; | 93 | ttype(key(&v[i])) = ttype(val(&v[i])) = LUA_T_NIL; |
94 | v[i].next = NULL; | ||
95 | } | ||
76 | return v; | 96 | return v; |
77 | } | 97 | } |
78 | 98 | ||
79 | 99 | ||
80 | Hash *luaH_new (int nhash) { | 100 | static void setnodevector (Hash *t, int size) { |
81 | Hash *const t = luaM_new(Hash); | 101 | t->node = hashnodecreate(size); |
82 | nhash = luaO_redimension(nhash*3/2); | 102 | t->size = size; |
83 | nodevector(t) = hashnodecreate(nhash); | 103 | t->firstfree = &t->node[size-1]; /* first free position to be used */ |
84 | nhash(t) = nhash; | 104 | L->nblocks += gcsize(size); |
85 | nuse(t) = 0; | 105 | } |
106 | |||
107 | |||
108 | Hash *luaH_new (int size) { | ||
109 | Hash *t = luaM_new(Hash); | ||
110 | setnodevector(t, luaO_redimension(size+1)); | ||
86 | t->htag = TagDefault; | 111 | t->htag = TagDefault; |
87 | t->next = L->roottable; | 112 | t->next = L->roottable; |
88 | L->roottable = t; | 113 | L->roottable = t; |
89 | t->marked = 0; | 114 | t->marked = 0; |
90 | L->nblocks += gcsize(nhash); | ||
91 | return t; | 115 | return t; |
92 | } | 116 | } |
93 | 117 | ||
94 | 118 | ||
95 | void luaH_free (Hash *t) { | 119 | void luaH_free (Hash *t) { |
96 | L->nblocks -= gcsize(t->nhash); | 120 | L->nblocks -= gcsize(t->size); |
97 | luaM_free(nodevector(t)); | 121 | luaM_free(t->node); |
98 | luaM_free(t); | 122 | luaM_free(t); |
99 | } | 123 | } |
100 | 124 | ||
101 | 125 | ||
102 | static int newsize (Hash *t) { | 126 | static int newsize (const Hash *t) { |
103 | Node *const v = t->node; | 127 | Node *v = t->node; |
104 | const int size = nhash(t); | 128 | int size = t->size; |
105 | int realuse = 0; | 129 | int realuse = 0; |
106 | int i; | 130 | int i; |
107 | for (i=0; i<size; i++) { | 131 | for (i=0; i<size; i++) { |
@@ -112,57 +136,158 @@ static int newsize (Hash *t) { | |||
112 | } | 136 | } |
113 | 137 | ||
114 | 138 | ||
115 | static void rehash (Hash *t) { | 139 | #ifdef DEBUG |
116 | const int nold = nhash(t); | 140 | /* check invariant of a table */ |
117 | Node *const vold = nodevector(t); | 141 | static int listfind (const Node *m, const Node *n) { |
118 | const int nnew = newsize(t); | 142 | do { |
119 | int i; | 143 | if (m==n) return 1; |
120 | nodevector(t) = hashnodecreate(nnew); | 144 | m = m->next; |
121 | nhash(t) = nnew; | 145 | } while (m); |
122 | nuse(t) = 0; | 146 | return 0; |
123 | for (i=0; i<nold; i++) { | 147 | } |
124 | Node *n = vold+i; | 148 | |
125 | if (ttype(val(n)) != LUA_T_NIL) { | 149 | static int check_invariant (const Hash *t, int filled) { |
126 | *luaH_present(t, ref(n)) = *n; /* copy old node to new hash */ | 150 | Node *n; |
127 | nuse(t)++; | 151 | for (n=t->node; n<t->firstfree; n++) { |
128 | } | 152 | TObject *key = &n->key; |
153 | LUA_ASSERT(ttype(key) == LUA_T_NIL || n == luaH_mainposition(t, key), | ||
154 | "all elements before firstfree are empty or in their main positions"); | ||
155 | } | ||
156 | if (!filled) | ||
157 | LUA_ASSERT(ttype(&(n++)->key) == LUA_T_NIL, "firstfree must be empty"); | ||
158 | else | ||
159 | LUA_ASSERT(n == t->node, "table cannot have empty places"); | ||
160 | for (; n<t->node+t->size; n++) { | ||
161 | TObject *key = &n->key; | ||
162 | Node *mp = luaH_mainposition(t, key); | ||
163 | LUA_ASSERT(ttype(key) != LUA_T_NIL, | ||
164 | "cannot exist empty elements after firstfree"); | ||
165 | LUA_ASSERT(n == mp || luaH_mainposition(t, &mp->key) == mp, | ||
166 | "either an element or its colliding element is in its main position"); | ||
167 | LUA_ASSERT(listfind(mp,n), "element is in its main position list"); | ||
129 | } | 168 | } |
130 | L->nblocks += gcsize(nnew)-gcsize(nold); | 169 | return 1; |
131 | luaM_free(vold); | ||
132 | } | 170 | } |
171 | #endif | ||
133 | 172 | ||
134 | 173 | ||
135 | void luaH_set (Hash *t, const TObject *ref, const TObject *val) { | 174 | /* |
136 | Node *const n = luaH_present(t, ref); | 175 | ** the rehash is done in two stages: first, we insert only the elements whose |
137 | *val(n) = *val; | 176 | ** main position is free, to avoid needless collisions. In the second stage, |
138 | if (ttype(ref(n)) == LUA_T_NIL) { /* new node? */ | 177 | ** we insert the other elements. |
139 | *ref(n) = *ref; /* set key */ | 178 | */ |
140 | nuse(t)++; /* count it */ | 179 | static void rehash (Hash *t) { |
141 | if ((long)nuse(t)*3L > (long)nhash(t)*2L) /* check size */ | 180 | int oldsize = t->size; |
142 | rehash(t); | 181 | Node *nold = t->node; |
182 | int i; | ||
183 | LUA_ASSERT(check_invariant(t, 1), "invalid table"); | ||
184 | L->nblocks -= gcsize(oldsize); | ||
185 | setnodevector(t, newsize(t)); /* create new array of nodes */ | ||
186 | /* first loop; set only elements that can go in their main positions */ | ||
187 | for (i=0; i<oldsize; i++) { | ||
188 | Node *old = nold+i; | ||
189 | if (ttype(&old->val) == LUA_T_NIL) | ||
190 | old->next = NULL; /* `remove' it for next loop */ | ||
191 | else { | ||
192 | Node *mp = luaH_mainposition(t, &old->key); /* new main position */ | ||
193 | if (ttype(&mp->key) == LUA_T_NIL) { /* is it empty? */ | ||
194 | mp->key = old->key; /* put element there */ | ||
195 | mp->val = old->val; | ||
196 | old->next = NULL; /* `remove' it for next loop */ | ||
197 | } | ||
198 | else /* it will be copied in next loop */ | ||
199 | old->next = mp; /* to be used in next loop */ | ||
200 | } | ||
143 | } | 201 | } |
202 | /* update `firstfree' */ | ||
203 | while (ttype(&t->firstfree->key) != LUA_T_NIL) t->firstfree--; | ||
204 | /* second loop; update elements with colision */ | ||
205 | for (i=0; i<oldsize; i++) { | ||
206 | Node *old = nold+i; | ||
207 | if (old->next) { /* wasn't already `removed'? */ | ||
208 | Node *mp = old->next; /* main position */ | ||
209 | Node *e = t->firstfree; /* actual position */ | ||
210 | e->key = old->key; /* put element in the free position */ | ||
211 | e->val = old->val; | ||
212 | e->next = mp->next; /* chain actual position in main position's list */ | ||
213 | mp->next = e; | ||
214 | do { /* update `firstfree' */ | ||
215 | t->firstfree--; | ||
216 | } while (ttype(&t->firstfree->key) != LUA_T_NIL); | ||
217 | } | ||
218 | } | ||
219 | LUA_ASSERT(check_invariant(t, 0), "invalid table"); | ||
220 | luaM_free(nold); /* free old array */ | ||
144 | } | 221 | } |
145 | 222 | ||
146 | 223 | ||
147 | int luaH_pos (const Hash *t, const TObject *r) { | 224 | /* |
148 | Node *const n = luaH_present(t, r); | 225 | ** sets a pair key-value in a hash table; first, check whether key is |
149 | luaL_arg_check(ttype(val(n)) != LUA_T_NIL, 2, "key not found"); | 226 | ** already present; if not, check whether key's main position is free; |
150 | return n-(t->node); | 227 | ** if not, check whether colliding node is in its main position or not; |
228 | ** if it is not, move colliding node to an empty place and put new pair | ||
229 | ** in its main position; otherwise (colliding node is in its main position), | ||
230 | ** new pair goes to an empty position. | ||
231 | ** Tricky point: the only place where an old element is moved is when | ||
232 | ** we move the colliding node to an empty place; nevertheless, its old | ||
233 | ** value is still in that position until we set the value for the new | ||
234 | ** pair; therefore, even when `val' points to an element of this table | ||
235 | ** (this happens when we use `luaH_move'), there is no problem. | ||
236 | */ | ||
237 | void luaH_set (Hash *t, const TObject *key, const TObject *val) { | ||
238 | Node *mp = luaH_mainposition(t, key); | ||
239 | Node *n = mp; | ||
240 | do { /* check whether `key' is somewhere in the chain */ | ||
241 | if (luaO_equalObj(key, &n->key)) { | ||
242 | n->val = *val; /* update value */ | ||
243 | return; /* that's all */ | ||
244 | } | ||
245 | else n = n->next; | ||
246 | } while (n); | ||
247 | /* `key' not found; must insert it */ | ||
248 | if (ttype(&mp->key) != LUA_T_NIL) { /* main position is not free? */ | ||
249 | Node *othern; /* main position of colliding node */ | ||
250 | n = t->firstfree; /* get a free place */ | ||
251 | /* is colliding node out of its main position? (can only happens if | ||
252 | its position if after "firstfree") */ | ||
253 | if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) { | ||
254 | /* yes; move colliding node into free position */ | ||
255 | while (othern->next != mp) othern = othern->next; /* find previous */ | ||
256 | othern->next = n; /* redo the chain with `n' in place of `mp' */ | ||
257 | *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ | ||
258 | mp->next = NULL; /* now `mp' is free */ | ||
259 | } | ||
260 | else { /* colliding node is in its own main position */ | ||
261 | /* new node will go into free position */ | ||
262 | n->next = mp->next; /* chain new position */ | ||
263 | mp->next = n; | ||
264 | mp = n; | ||
265 | } | ||
266 | } | ||
267 | mp->key = *key; | ||
268 | mp->val = *val; | ||
269 | for (;;) { /* check free places */ | ||
270 | if (ttype(&(t->firstfree)->key) == LUA_T_NIL) | ||
271 | return; /* OK; table still has a free place */ | ||
272 | else if (t->firstfree == t->node) break; /* cannot decrement from here */ | ||
273 | else (t->firstfree)--; | ||
274 | } | ||
275 | rehash(t); /* no more free places */ | ||
151 | } | 276 | } |
152 | 277 | ||
153 | 278 | ||
154 | void luaH_setint (Hash *t, int ref, const TObject *val) { | 279 | void luaH_setint (Hash *t, int key, const TObject *val) { |
155 | TObject index; | 280 | TObject index; |
156 | ttype(&index) = LUA_T_NUMBER; | 281 | ttype(&index) = LUA_T_NUMBER; |
157 | nvalue(&index) = ref; | 282 | nvalue(&index) = key; |
158 | luaH_set(t, &index, val); | 283 | luaH_set(t, &index, val); |
159 | } | 284 | } |
160 | 285 | ||
161 | 286 | ||
162 | TObject *luaH_getint (const Hash *t, int ref) { | 287 | const TObject *luaH_getint (const Hash *t, int key) { |
163 | TObject index; | 288 | TObject index; |
164 | ttype(&index) = LUA_T_NUMBER; | 289 | ttype(&index) = LUA_T_NUMBER; |
165 | nvalue(&index) = ref; | 290 | nvalue(&index) = key; |
166 | return luaH_get(t, &index); | 291 | return luaH_get(t, &index); |
167 | } | 292 | } |
168 | 293 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.h,v 1.12 1999/08/16 20:52:00 roberto Exp roberto $ | 2 | ** $Id: ltable.h,v 1.13 1999/10/04 17:51:04 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -11,20 +11,19 @@ | |||
11 | 11 | ||
12 | 12 | ||
13 | #define node(t,i) (&(t)->node[i]) | 13 | #define node(t,i) (&(t)->node[i]) |
14 | #define ref(n) (&(n)->ref) | 14 | #define key(n) (&(n)->key) |
15 | #define val(n) (&(n)->val) | 15 | #define val(n) (&(n)->val) |
16 | #define nhash(t) ((t)->nhash) | ||
17 | 16 | ||
18 | #define luaH_get(t,ref) (val(luaH_present((t), (ref)))) | ||
19 | #define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from))) | 17 | #define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from))) |
20 | 18 | ||
21 | Hash *luaH_new (int nhash); | 19 | Hash *luaH_new (int nhash); |
22 | void luaH_free (Hash *t); | 20 | void luaH_free (Hash *t); |
23 | Node *luaH_present (const Hash *t, const TObject *key); | 21 | const TObject *luaH_get (const Hash *t, const TObject *key); |
24 | void luaH_set (Hash *t, const TObject *ref, const TObject *val); | 22 | void luaH_set (Hash *t, const TObject *key, const TObject *val); |
25 | int luaH_pos (const Hash *t, const TObject *r); | 23 | int luaH_pos (const Hash *t, const TObject *r); |
26 | void luaH_setint (Hash *t, int ref, const TObject *val); | 24 | void luaH_setint (Hash *t, int key, const TObject *val); |
27 | TObject *luaH_getint (const Hash *t, int ref); | 25 | const TObject *luaH_getint (const Hash *t, int key); |
26 | unsigned long luaH_hash (const TObject *key); /* exported only for debugging */ | ||
28 | 27 | ||
29 | 28 | ||
30 | #endif | 29 | #endif |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 1.61 1999/09/06 13:55:09 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.62 1999/09/17 16:53:54 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -107,7 +107,7 @@ void luaV_gettable (void) { | |||
107 | int tg = table->value.a->htag; | 107 | int tg = table->value.a->htag; |
108 | im = luaT_getim(tg, IM_GETTABLE); | 108 | im = luaT_getim(tg, IM_GETTABLE); |
109 | if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ | 109 | if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ |
110 | TObject *h = luaH_get(avalue(table), table+1); | 110 | const TObject *h = luaH_get(avalue(table), table+1); |
111 | if (ttype(h) == LUA_T_NIL && | 111 | if (ttype(h) == LUA_T_NIL && |
112 | (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)) { | 112 | (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)) { |
113 | /* result is nil and there is an "index" tag method */ | 113 | /* result is nil and there is an "index" tag method */ |