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.
Diffstat (limited to '')
| -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 */ |
