ltable.c
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:9k
源码类别:

模拟服务器

开发平台:

C/C++

  1. /*
  2. ** $Id: ltable.c,v 1.58 2000/10/26 12:47:05 roberto Exp $
  3. ** Lua tables (hash)
  4. ** See Copyright Notice in lua.h
  5. */
  6. /*
  7. ** Implementation of tables (aka arrays, objects, or hash tables);
  8. ** uses a mix of chained scatter table with Brent's variation.
  9. ** A main invariant of these tables is that, if an element is not
  10. ** in its main position (i.e. the `original' position that its hash gives
  11. ** to it), then the colliding element is in its own main position.
  12. ** In other words, there are collisions only when two elements have the
  13. ** same main position (i.e. the same hash values for that table size).
  14. ** Because of that, the load factor of these tables can be 100% without
  15. ** performance penalties.
  16. */
  17. #include "lua.h"
  18. #include "lmem.h"
  19. #include "lobject.h"
  20. #include "lstate.h"
  21. #include "lstring.h"
  22. #include "ltable.h"
  23. #define gcsize(L, n) (sizeof(Hash)+(n)*sizeof(Node))
  24. #define TagDefault LUA_TTABLE
  25. /*
  26. ** returns the `main' position of an element in a table (that is, the index
  27. ** of its hash value)
  28. */
  29. Node *luaH_mainposition (const Hash *t, const TObject *key) {
  30.   unsigned long h;
  31.   switch (ttype(key)) {
  32.     case LUA_TNUMBER:
  33.       h = (unsigned long)(long)nvalue(key);
  34.       break;
  35.     case LUA_TSTRING:
  36.       h = tsvalue(key)->u.s.hash;
  37.       break;
  38.     case LUA_TUSERDATA:
  39.       h = IntPoint(tsvalue(key));
  40.       break;
  41.     case LUA_TTABLE:
  42.       h = IntPoint(hvalue(key));
  43.       break;
  44.     case LUA_TFUNCTION:
  45.       h = IntPoint(clvalue(key));
  46.       break;
  47.     default:
  48.       return NULL;  /* invalid key */
  49.   }
  50.   LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)),
  51.             "a&(x-1) == a%x, for x power of 2");
  52.   return &t->node[h&(t->size-1)];
  53. }
  54. static const TObject *luaH_getany (lua_State *L, const Hash *t,
  55.                                    const TObject *key) {
  56.   Node *n = luaH_mainposition(t, key);
  57.   if (!n)
  58.     lua_error(L, "table index is nil");
  59.   else do {
  60.     if (luaO_equalObj(key, &n->key))
  61.       return &n->val;
  62.     n = n->next;
  63.   } while (n);
  64.   return &luaO_nilobject;  /* key not found */
  65. }
  66. /* specialized version for numbers */
  67. const TObject *luaH_getnum (const Hash *t, Number key) {
  68.   Node *n = &t->node[(unsigned long)(long)key&(t->size-1)];
  69.   do {
  70.     if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key)
  71.       return &n->val;
  72.     n = n->next;
  73.   } while (n);
  74.   return &luaO_nilobject;  /* key not found */
  75. }
  76. /* specialized version for strings */
  77. const TObject *luaH_getstr (const Hash *t, TString *key) {
  78.   Node *n = &t->node[key->u.s.hash&(t->size-1)];
  79.   do {
  80.     if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key)
  81.       return &n->val;
  82.     n = n->next;
  83.   } while (n);
  84.   return &luaO_nilobject;  /* key not found */
  85. }
  86. const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) {
  87.   switch (ttype(key)) {
  88.     case LUA_TNUMBER: return luaH_getnum(t, nvalue(key));
  89.     case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
  90.     default:         return luaH_getany(L, t, key);
  91.   }
  92. }
  93. Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) {
  94.   int i;
  95.   if (ttype(key) == LUA_TNIL)
  96.     i = 0;  /* first iteration */
  97.   else {
  98.     const TObject *v = luaH_get(L, t, key);
  99.     if (v == &luaO_nilobject)
  100.       lua_error(L, "invalid key for `next'");
  101.     i = (int)(((const char *)v -
  102.                (const char *)(&t->node[0].val)) / sizeof(Node)) + 1;
  103.   }
  104.   for (; i<t->size; i++) {
  105.     Node *n = node(t, i);
  106.     if (ttype(val(n)) != LUA_TNIL)
  107.       return n;
  108.   }
  109.   return NULL;  /* no more elements */
  110. }
  111. /*
  112. ** try to remove a key without value from a table. To avoid problems with
  113. ** hash, change `key' for a number with the same hash.
  114. */
  115. void luaH_remove (Hash *t, TObject *key) {
  116.   if (ttype(key) == LUA_TNUMBER ||
  117.        (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30))
  118.   return;  /* do not remove numbers nor small strings */
  119.   else {
  120.     /* try to find a number `n' with the same hash as `key' */
  121.     Node *mp = luaH_mainposition(t, key);
  122.     int n = mp - &t->node[0];
  123.     /* make sure `n' is not in `t' */
  124.     while (luaH_getnum(t, n) != &luaO_nilobject) {
  125.       if (n >= MAX_INT - t->size)
  126.         return;  /* give up; (to avoid overflow) */
  127.       n += t->size;
  128.     }
  129.     ttype(key) = LUA_TNUMBER;
  130.     nvalue(key) = n;
  131.     LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash");
  132.   }
  133. }
  134. static void setnodevector (lua_State *L, Hash *t, lint32 size) {
  135.   int i;
  136.   if (size > MAX_INT)
  137.     lua_error(L, "table overflow");
  138.   t->node = luaM_newvector(L, size, Node);
  139.   for (i=0; i<(int)size; i++) {
  140.     ttype(&t->node[i].key) = ttype(&t->node[i].val) = LUA_TNIL;
  141.     t->node[i].next = NULL;
  142.   }
  143.   L->nblocks += gcsize(L, size) - gcsize(L, t->size);
  144.   t->size = size;
  145.   t->firstfree = &t->node[size-1];  /* first free position to be used */
  146. }
  147. Hash *luaH_new (lua_State *L, int size) {
  148.   Hash *t = luaM_new(L, Hash);
  149.   t->htag = TagDefault;
  150.   t->next = L->roottable;
  151.   L->roottable = t;
  152.   t->mark = t;
  153.   t->size = 0;
  154.   L->nblocks += gcsize(L, 0);
  155.   t->node = NULL;
  156.   setnodevector(L, t, luaO_power2(size));
  157.   return t;
  158. }
  159. void luaH_free (lua_State *L, Hash *t) {
  160.   L->nblocks -= gcsize(L, t->size);
  161.   luaM_free(L, t->node);
  162.   luaM_free(L, t);
  163. }
  164. static int numuse (const Hash *t) {
  165.   Node *v = t->node;
  166.   int size = t->size;
  167.   int realuse = 0;
  168.   int i;
  169.   for (i=0; i<size; i++) {
  170.     if (ttype(&v[i].val) != LUA_TNIL)
  171.       realuse++;
  172.   }
  173.   return realuse;
  174. }
  175. static void rehash (lua_State *L, Hash *t) {
  176.   int oldsize = t->size;
  177.   Node *nold = t->node;
  178.   int nelems = numuse(t);
  179.   int i;
  180.   LUA_ASSERT(nelems<=oldsize, "wrong count");
  181.   if (nelems >= oldsize-oldsize/4)  /* using more than 3/4? */
  182.     setnodevector(L, t, (lint32)oldsize*2);
  183.   else if (nelems <= oldsize/4 &&  /* less than 1/4? */
  184.            oldsize > MINPOWER2)
  185.     setnodevector(L, t, oldsize/2);
  186.   else
  187.     setnodevector(L, t, oldsize);
  188.   for (i=0; i<oldsize; i++) {
  189.     Node *old = nold+i;
  190.     if (ttype(&old->val) != LUA_TNIL)
  191.       *luaH_set(L, t, &old->key) = old->val;
  192.   }
  193.   luaM_free(L, nold);  /* free old array */
  194. }
  195. /*
  196. ** inserts a key into a hash table; first, check whether key is
  197. ** already present; if not, check whether key's main position is free;
  198. ** if not, check whether colliding node is in its main position or not;
  199. ** if it is not, move colliding node to an empty place and put new key
  200. ** in its main position; otherwise (colliding node is in its main position),
  201. ** new key goes to an empty position.
  202. */
  203. TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) {
  204.   Node *mp = luaH_mainposition(t, key);
  205.   Node *n = mp;
  206.   if (!mp)
  207.     lua_error(L, "table index is nil");
  208.   do {  /* check whether `key' is somewhere in the chain */
  209.     if (luaO_equalObj(key, &n->key))
  210.       return &n->val;  /* that's all */
  211.     else n = n->next;
  212.   } while (n);
  213.   /* `key' not found; must insert it */
  214.   if (ttype(&mp->key) != LUA_TNIL) {  /* main position is not free? */
  215.     Node *othern;  /* main position of colliding node */
  216.     n = t->firstfree;  /* get a free place */
  217.     /* is colliding node out of its main position? (can only happens if
  218.        its position is after "firstfree") */
  219.     if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) {
  220.       /* yes; move colliding node into free position */
  221.       while (othern->next != mp) othern = othern->next;  /* find previous */
  222.       othern->next = n;  /* redo the chain with `n' in place of `mp' */
  223.       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
  224.       mp->next = NULL;  /* now `mp' is free */
  225.     }
  226.     else {  /* colliding node is in its own main position */
  227.       /* new node will go into free position */
  228.       n->next = mp->next;  /* chain new position */
  229.       mp->next = n;
  230.       mp = n;
  231.     }
  232.   }
  233.   mp->key = *key;
  234.   for (;;) {  /* correct `firstfree' */
  235.     if (ttype(&t->firstfree->key) == LUA_TNIL)
  236.       return &mp->val;  /* OK; table still has a free place */
  237.     else if (t->firstfree == t->node) break;  /* cannot decrement from here */
  238.     else (t->firstfree)--;
  239.   }
  240.   rehash(L, t);  /* no more free places */
  241.   return luaH_set(L, t, key);  /* `rehash' invalidates this insertion */
  242. }
  243. TObject *luaH_setint (lua_State *L, Hash *t, int key) {
  244.   TObject index;
  245.   ttype(&index) = LUA_TNUMBER;
  246.   nvalue(&index) = key;
  247.   return luaH_set(L, t, &index);
  248. }
  249. void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val) {
  250.   TObject *value, index;
  251.   ttype(&index) = LUA_TSTRING;
  252.   tsvalue(&index) = key;
  253.   value = luaH_set(L, t, &index);
  254.   ttype(value) = LUA_TNUMBER;
  255.   nvalue(value) = val;
  256. }
  257. const TObject *luaH_getglobal (lua_State *L, const char *name) {
  258.   return luaH_getstr(L->gt, luaS_new(L, name));
  259. }