lua/ltable.c

Go to the documentation of this file.
00001 /*
00002 ** $Id: ltable.c,v 2.67 2011/11/30 12:41:45 roberto Exp $
00003 ** Lua tables (hash)
00004 ** See Copyright Notice in lua.h
00005 */
00006 
00007 
00008 /*
00009 ** Implementation of tables (aka arrays, objects, or hash tables).
00010 ** Tables keep its elements in two parts: an array part and a hash part.
00011 ** Non-negative integer keys are all candidates to be kept in the array
00012 ** part. The actual size of the array is the largest `n' such that at
00013 ** least half the slots between 0 and n are in use.
00014 ** Hash uses a mix of chained scatter table with Brent's variation.
00015 ** A main invariant of these tables is that, if an element is not
00016 ** in its main position (i.e. the `original' position that its hash gives
00017 ** to it), then the colliding element is in its own main position.
00018 ** Hence even when the load factor reaches 100%, performance remains good.
00019 */
00020 
00021 #include <string.h>
00022 
00023 #define ltable_c
00024 #define LUA_CORE
00025 
00026 #include "lua.h"
00027 
00028 #include "ldebug.h"
00029 #include "ldo.h"
00030 #include "lgc.h"
00031 #include "lmem.h"
00032 #include "lobject.h"
00033 #include "lstate.h"
00034 #include "lstring.h"
00035 #include "ltable.h"
00036 #include "lvm.h"
00037 
00038 
00039 /*
00040 ** max size of array part is 2^MAXBITS
00041 */
00042 #if LUAI_BITSINT >= 32
00043 #define MAXBITS     30
00044 #else
00045 #define MAXBITS     (LUAI_BITSINT-2)
00046 #endif
00047 
00048 #define MAXASIZE    (1 << MAXBITS)
00049 
00050 
00051 #define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t))))
00052 
00053 #define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
00054 #define hashboolean(t,p)        hashpow2(t, p)
00055 
00056 
00057 /*
00058 ** for some types, it is better to avoid modulus by power of 2, as
00059 ** they tend to have many 2 factors.
00060 */
00061 #define hashmod(t,n)    (gnode(t, ((n) % ((sizenode(t)-1)|1))))
00062 
00063 
00064 #define hashpointer(t,p)    hashmod(t, IntPoint(p))
00065 
00066 
00067 #define dummynode       (&dummynode_)
00068 
00069 #define isdummy(n)      ((n) == dummynode)
00070 
00071 static const Node dummynode_ = {
00072   {NILCONSTANT},  /* value */
00073   {{NILCONSTANT, NULL}}  /* key */
00074 };
00075 
00076 
00077 /*
00078 ** hash for lua_Numbers
00079 */
00080 static Node *hashnum (const Table *t, lua_Number n) {
00081   int i;
00082   luai_hashnum(i, n);
00083   if (i < 0) {
00084     if (cast(unsigned int, i) == 0u - i)  /* use unsigned to avoid overflows */
00085       i = 0;  /* handle INT_MIN */
00086     i = -i;  /* must be a positive value */
00087   }
00088   return hashmod(t, i);
00089 }
00090 
00091 
00092 
00093 /*
00094 ** returns the `main' position of an element in a table (that is, the index
00095 ** of its hash value)
00096 */
00097 static Node *mainposition (const Table *t, const TValue *key) {
00098   switch (ttype(key)) {
00099     case LUA_TNUMBER:
00100       return hashnum(t, nvalue(key));
00101     case LUA_TSTRING:
00102       return hashstr(t, rawtsvalue(key));
00103     case LUA_TBOOLEAN:
00104       return hashboolean(t, bvalue(key));
00105     case LUA_TLIGHTUSERDATA:
00106       return hashpointer(t, pvalue(key));
00107     case LUA_TLCF:
00108       return hashpointer(t, fvalue(key));
00109     default:
00110       return hashpointer(t, gcvalue(key));
00111   }
00112 }
00113 
00114 
00115 /*
00116 ** returns the index for `key' if `key' is an appropriate key to live in
00117 ** the array part of the table, -1 otherwise.
00118 */
00119 static int arrayindex (const TValue *key) {
00120   if (ttisnumber(key)) {
00121     lua_Number n = nvalue(key);
00122     int k;
00123     lua_number2int(k, n);
00124     if (luai_numeq(cast_num(k), n))
00125       return k;
00126   }
00127   return -1;  /* `key' did not match some condition */
00128 }
00129 
00130 
00131 /*
00132 ** returns the index of a `key' for table traversals. First goes all
00133 ** elements in the array part, then elements in the hash part. The
00134 ** beginning of a traversal is signaled by -1.
00135 */
00136 static int findindex (lua_State *L, Table *t, StkId key) {
00137   int i;
00138   if (ttisnil(key)) return -1;  /* first iteration */
00139   i = arrayindex(key);
00140   if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */
00141     return i-1;  /* yes; that's the index (corrected to C) */
00142   else {
00143     Node *n = mainposition(t, key);
00144     for (;;) {  /* check whether `key' is somewhere in the chain */
00145       /* key may be dead already, but it is ok to use it in `next' */
00146       if (luaV_rawequalobj(gkey(n), key) ||
00147             (ttisdeadkey(gkey(n)) && iscollectable(key) &&
00148              deadvalue(gkey(n)) == gcvalue(key))) {
00149         i = cast_int(n - gnode(t, 0));  /* key index in hash table */
00150         /* hash elements are numbered after array ones */
00151         return i + t->sizearray;
00152       }
00153       else n = gnext(n);
00154       if (n == NULL)
00155         luaG_runerror(L, "invalid key to " LUA_QL("next"));  /* key not found */
00156     }
00157   }
00158 }
00159 
00160 
00161 int luaH_next (lua_State *L, Table *t, StkId key) {
00162   int i = findindex(L, t, key);  /* find original element */
00163   for (i++; i < t->sizearray; i++) {  /* try first array part */
00164     if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
00165       setnvalue(key, cast_num(i+1));
00166       setobj2s(L, key+1, &t->array[i]);
00167       return 1;
00168     }
00169   }
00170   for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */
00171     if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */
00172       setobj2s(L, key, gkey(gnode(t, i)));
00173       setobj2s(L, key+1, gval(gnode(t, i)));
00174       return 1;
00175     }
00176   }
00177   return 0;  /* no more elements */
00178 }
00179 
00180 
00181 /*
00182 ** {=============================================================
00183 ** Rehash
00184 ** ==============================================================
00185 */
00186 
00187 
00188 static int computesizes (int nums[], int *narray) {
00189   int i;
00190   int twotoi;  /* 2^i */
00191   int a = 0;  /* number of elements smaller than 2^i */
00192   int na = 0;  /* number of elements to go to array part */
00193   int n = 0;  /* optimal size for array part */
00194   for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
00195     if (nums[i] > 0) {
00196       a += nums[i];
00197       if (a > twotoi/2) {  /* more than half elements present? */
00198         n = twotoi;  /* optimal size (till now) */
00199         na = a;  /* all elements smaller than n will go to array part */
00200       }
00201     }
00202     if (a == *narray) break;  /* all elements already counted */
00203   }
00204   *narray = n;
00205   lua_assert(*narray/2 <= na && na <= *narray);
00206   return na;
00207 }
00208 
00209 
00210 static int countint (const TValue *key, int *nums) {
00211   int k = arrayindex(key);
00212   if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */
00213     nums[luaO_ceillog2(k)]++;  /* count as such */
00214     return 1;
00215   }
00216   else
00217     return 0;
00218 }
00219 
00220 
00221 static int numusearray (const Table *t, int *nums) {
00222   int lg;
00223   int ttlg;  /* 2^lg */
00224   int ause = 0;  /* summation of `nums' */
00225   int i = 1;  /* count to traverse all array keys */
00226   for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */
00227     int lc = 0;  /* counter */
00228     int lim = ttlg;
00229     if (lim > t->sizearray) {
00230       lim = t->sizearray;  /* adjust upper limit */
00231       if (i > lim)
00232         break;  /* no more elements to count */
00233     }
00234     /* count elements in range (2^(lg-1), 2^lg] */
00235     for (; i <= lim; i++) {
00236       if (!ttisnil(&t->array[i-1]))
00237         lc++;
00238     }
00239     nums[lg] += lc;
00240     ause += lc;
00241   }
00242   return ause;
00243 }
00244 
00245 
00246 static int numusehash (const Table *t, int *nums, int *pnasize) {
00247   int totaluse = 0;  /* total number of elements */
00248   int ause = 0;  /* summation of `nums' */
00249   int i = sizenode(t);
00250   while (i--) {
00251     Node *n = &t->node[i];
00252     if (!ttisnil(gval(n))) {
00253       ause += countint(gkey(n), nums);
00254       totaluse++;
00255     }
00256   }
00257   *pnasize += ause;
00258   return totaluse;
00259 }
00260 
00261 
00262 static void setarrayvector (lua_State *L, Table *t, int size) {
00263   int i;
00264   luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
00265   for (i=t->sizearray; i<size; i++)
00266      setnilvalue(&t->array[i]);
00267   t->sizearray = size;
00268 }
00269 
00270 
00271 static void setnodevector (lua_State *L, Table *t, int size) {
00272   int lsize;
00273   if (size == 0) {  /* no elements to hash part? */
00274     t->node = cast(Node *, dummynode);  /* use common `dummynode' */
00275     lsize = 0;
00276   }
00277   else {
00278     int i;
00279     lsize = luaO_ceillog2(size);
00280     if (lsize > MAXBITS)
00281       luaG_runerror(L, "table overflow");
00282     size = twoto(lsize);
00283     t->node = luaM_newvector(L, size, Node);
00284     for (i=0; i<size; i++) {
00285       Node *n = gnode(t, i);
00286       gnext(n) = NULL;
00287       setnilvalue(gkey(n));
00288       setnilvalue(gval(n));
00289     }
00290   }
00291   t->lsizenode = cast_byte(lsize);
00292   t->lastfree = gnode(t, size);  /* all positions are free */
00293 }
00294 
00295 
00296 void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) {
00297   int i;
00298   int oldasize = t->sizearray;
00299   int oldhsize = t->lsizenode;
00300   Node *nold = t->node;  /* save old hash ... */
00301   if (nasize > oldasize)  /* array part must grow? */
00302     setarrayvector(L, t, nasize);
00303   /* create new hash part with appropriate size */
00304   setnodevector(L, t, nhsize);
00305   if (nasize < oldasize) {  /* array part must shrink? */
00306     t->sizearray = nasize;
00307     /* re-insert elements from vanishing slice */
00308     for (i=nasize; i<oldasize; i++) {
00309       if (!ttisnil(&t->array[i]))
00310         luaH_setint(L, t, i + 1, &t->array[i]);
00311     }
00312     /* shrink array */
00313     luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
00314   }
00315   /* re-insert elements from hash part */
00316   for (i = twoto(oldhsize) - 1; i >= 0; i--) {
00317     Node *old = nold+i;
00318     if (!ttisnil(gval(old))) {
00319       /* doesn't need barrier/invalidate cache, as entry was
00320          already present in the table */
00321       setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
00322     }
00323   }
00324   if (!isdummy(nold))
00325     luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
00326 }
00327 
00328 
00329 void luaH_resizearray (lua_State *L, Table *t, int nasize) {
00330   int nsize = isdummy(t->node) ? 0 : sizenode(t);
00331   luaH_resize(L, t, nasize, nsize);
00332 }
00333 
00334 
00335 static void rehash (lua_State *L, Table *t, const TValue *ek) {
00336   int nasize, na;
00337   int nums[MAXBITS+1];  /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */
00338   int i;
00339   int totaluse;
00340   for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */
00341   nasize = numusearray(t, nums);  /* count keys in array part */
00342   totaluse = nasize;  /* all those keys are integer keys */
00343   totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */
00344   /* count extra key */
00345   nasize += countint(ek, nums);
00346   totaluse++;
00347   /* compute new size for array part */
00348   na = computesizes(nums, &nasize);
00349   /* resize the table to new computed sizes */
00350   luaH_resize(L, t, nasize, totaluse - na);
00351 }
00352 
00353 
00354 
00355 /*
00356 ** }=============================================================
00357 */
00358 
00359 
00360 Table *luaH_new (lua_State *L) {
00361   Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h;
00362   t->metatable = NULL;
00363   t->flags = cast_byte(~0);
00364   t->array = NULL;
00365   t->sizearray = 0;
00366   setnodevector(L, t, 0);
00367   return t;
00368 }
00369 
00370 
00371 void luaH_free (lua_State *L, Table *t) {
00372   if (!isdummy(t->node))
00373     luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
00374   luaM_freearray(L, t->array, t->sizearray);
00375   luaM_free(L, t);
00376 }
00377 
00378 
00379 static Node *getfreepos (Table *t) {
00380   while (t->lastfree > t->node) {
00381     t->lastfree--;
00382     if (ttisnil(gkey(t->lastfree)))
00383       return t->lastfree;
00384   }
00385   return NULL;  /* could not find a free place */
00386 }
00387 
00388 
00389 
00390 /*
00391 ** inserts a new key into a hash table; first, check whether key's main
00392 ** position is free. If not, check whether colliding node is in its main
00393 ** position or not: if it is not, move colliding node to an empty place and
00394 ** put new key in its main position; otherwise (colliding node is in its main
00395 ** position), new key goes to an empty position.
00396 */
00397 TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
00398   Node *mp;
00399   if (ttisnil(key)) luaG_runerror(L, "table index is nil");
00400   else if (ttisnumber(key) && luai_numisnan(L, nvalue(key)))
00401     luaG_runerror(L, "table index is NaN");
00402   mp = mainposition(t, key);
00403   if (!ttisnil(gval(mp)) || isdummy(mp)) {  /* main position is taken? */
00404     Node *othern;
00405     Node *n = getfreepos(t);  /* get a free place */
00406     if (n == NULL) {  /* cannot find a free place? */
00407       rehash(L, t, key);  /* grow table */
00408       /* whatever called 'newkey' take care of TM cache and GC barrier */
00409       return luaH_set(L, t, key);  /* insert key into grown table */
00410     }
00411     lua_assert(!isdummy(n));
00412     othern = mainposition(t, gkey(mp));
00413     if (othern != mp) {  /* is colliding node out of its main position? */
00414       /* yes; move colliding node into free position */
00415       while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
00416       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
00417       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
00418       gnext(mp) = NULL;  /* now `mp' is free */
00419       setnilvalue(gval(mp));
00420     }
00421     else {  /* colliding node is in its own main position */
00422       /* new node will go into free position */
00423       gnext(n) = gnext(mp);  /* chain new position */
00424       gnext(mp) = n;
00425       mp = n;
00426     }
00427   }
00428   setobj2t(L, gkey(mp), key);
00429   luaC_barrierback(L, obj2gco(t), key);
00430   lua_assert(ttisnil(gval(mp)));
00431   return gval(mp);
00432 }
00433 
00434 
00435 /*
00436 ** search function for integers
00437 */
00438 const TValue *luaH_getint (Table *t, int key) {
00439   /* (1 <= key && key <= t->sizearray) */
00440   if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
00441     return &t->array[key-1];
00442   else {
00443     lua_Number nk = cast_num(key);
00444     Node *n = hashnum(t, nk);
00445     do {  /* check whether `key' is somewhere in the chain */
00446       if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
00447         return gval(n);  /* that's it */
00448       else n = gnext(n);
00449     } while (n);
00450     return luaO_nilobject;
00451   }
00452 }
00453 
00454 
00455 /*
00456 ** search function for strings
00457 */
00458 const TValue *luaH_getstr (Table *t, TString *key) {
00459   Node *n = hashstr(t, key);
00460   do {  /* check whether `key' is somewhere in the chain */
00461     if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key))
00462       return gval(n);  /* that's it */
00463     else n = gnext(n);
00464   } while (n);
00465   return luaO_nilobject;
00466 }
00467 
00468 
00469 /*
00470 ** main search function
00471 */
00472 const TValue *luaH_get (Table *t, const TValue *key) {
00473   switch (ttypenv(key)) {
00474     case LUA_TNIL: return luaO_nilobject;
00475     case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
00476     case LUA_TNUMBER: {
00477       int k;
00478       lua_Number n = nvalue(key);
00479       lua_number2int(k, n);
00480       if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
00481         return luaH_getint(t, k);  /* use specialized version */
00482       /* else go through */
00483     }
00484     default: {
00485       Node *n = mainposition(t, key);
00486       do {  /* check whether `key' is somewhere in the chain */
00487         if (luaV_rawequalobj(gkey(n), key))
00488           return gval(n);  /* that's it */
00489         else n = gnext(n);
00490       } while (n);
00491       return luaO_nilobject;
00492     }
00493   }
00494 }
00495 
00496 
00497 /*
00498 ** beware: when using this function you probably need to check a GC
00499 ** barrier and invalidate the TM cache.
00500 */
00501 TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
00502   const TValue *p = luaH_get(t, key);
00503   if (p != luaO_nilobject)
00504     return cast(TValue *, p);
00505   else return luaH_newkey(L, t, key);
00506 }
00507 
00508 
00509 void luaH_setint (lua_State *L, Table *t, int key, TValue *value) {
00510   const TValue *p = luaH_getint(t, key);
00511   TValue *cell;
00512   if (p != luaO_nilobject)
00513     cell = cast(TValue *, p);
00514   else {
00515     TValue k;
00516     setnvalue(&k, cast_num(key));
00517     cell = luaH_newkey(L, t, &k);
00518   }
00519   setobj2t(L, cell, value);
00520 }
00521 
00522 
00523 static int unbound_search (Table *t, unsigned int j) {
00524   unsigned int i = j;  /* i is zero or a present index */
00525   j++;
00526   /* find `i' and `j' such that i is present and j is not */
00527   while (!ttisnil(luaH_getint(t, j))) {
00528     i = j;
00529     j *= 2;
00530     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
00531       /* table was built with bad purposes: resort to linear search */
00532       i = 1;
00533       while (!ttisnil(luaH_getint(t, i))) i++;
00534       return i - 1;
00535     }
00536   }
00537   /* now do a binary search between them */
00538   while (j - i > 1) {
00539     unsigned int m = (i+j)/2;
00540     if (ttisnil(luaH_getint(t, m))) j = m;
00541     else i = m;
00542   }
00543   return i;
00544 }
00545 
00546 
00547 /*
00548 ** Try to find a boundary in table `t'. A `boundary' is an integer index
00549 ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
00550 */
00551 int luaH_getn (Table *t) {
00552   unsigned int j = t->sizearray;
00553   if (j > 0 && ttisnil(&t->array[j - 1])) {
00554     /* there is a boundary in the array part: (binary) search for it */
00555     unsigned int i = 0;
00556     while (j - i > 1) {
00557       unsigned int m = (i+j)/2;
00558       if (ttisnil(&t->array[m - 1])) j = m;
00559       else i = m;
00560     }
00561     return i;
00562   }
00563   /* else must find a boundary in hash part */
00564   else if (isdummy(t->node))  /* hash part is empty? */
00565     return j;  /* that is easy... */
00566   else return unbound_search(t, j);
00567 }
00568 
00569 
00570 
00571 #if defined(LUA_DEBUG)
00572 
00573 Node *luaH_mainposition (const Table *t, const TValue *key) {
00574   return mainposition(t, key);
00575 }
00576 
00577 int luaH_isdummy (Node *n) { return isdummy(n); }
00578 
00579 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:04 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs