Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/lua-5.0.3/lua/ltable.c @ 1803

Last change on this file since 1803 was 1803, checked in by rgrieder, 16 years ago

added files for lua 5.1.3, lua 5.0.3, CEGUILua-0.6.1 and CEGUILua-0.5.0b

  • Property svn:eol-style set to native
File size: 14.3 KB
Line 
1/*
2** $Id: ltable.c,v 1.132 2003/04/03 13:35:34 roberto Exp $
3** Lua tables (hash)
4** See Copyright Notice in lua.h
5*/
6
7
8/*
9** Implementation of tables (aka arrays, objects, or hash tables).
10** Tables keep its elements in two parts: an array part and a hash part.
11** Non-negative integer keys are all candidates to be kept in the array
12** part. The actual size of the array is the largest `n' such that at
13** least half the slots between 0 and n are in use.
14** Hash uses a mix of chained scatter table with Brent's variation.
15** A main invariant of these tables is that, if an element is not
16** in its main position (i.e. the `original' position that its hash gives
17** to it), then the colliding element is in its own main position.
18** In other words, there are collisions only when two elements have the
19** same main position (i.e. the same hash values for that table size).
20** Because of that, the load factor of these tables can be 100% without
21** performance penalties.
22*/
23
24#include <string.h>
25
26#define ltable_c
27
28#include "lua.h"
29
30#include "ldebug.h"
31#include "ldo.h"
32#include "lgc.h"
33#include "lmem.h"
34#include "lobject.h"
35#include "lstate.h"
36#include "ltable.h"
37
38
39/*
40** max size of array part is 2^MAXBITS
41*/
42#if BITS_INT > 26
43#define MAXBITS         24
44#else
45#define MAXBITS         (BITS_INT-2)
46#endif
47
48/* check whether `x' < 2^MAXBITS */
49#define toobig(x)       ((((x)-1) >> MAXBITS) != 0)
50
51
52/* function to convert a lua_Number to int (with any rounding method) */
53#ifndef lua_number2int
54#define lua_number2int(i,n)     ((i)=(int)(n))
55#endif
56
57
58#define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t))))
59 
60#define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
61#define hashboolean(t,p)        hashpow2(t, p)
62
63
64/*
65** for some types, it is better to avoid modulus by power of 2, as
66** they tend to have many 2 factors.
67*/
68#define hashmod(t,n)    (gnode(t, ((n) % ((sizenode(t)-1)|1))))
69
70
71#define hashpointer(t,p)        hashmod(t, IntPoint(p))
72
73
74/*
75** number of ints inside a lua_Number
76*/
77#define numints         cast(int, sizeof(lua_Number)/sizeof(int))
78
79
80/*
81** hash for lua_Numbers
82*/
83static Node *hashnum (const Table *t, lua_Number n) {
84  unsigned int a[numints];
85  int i;
86  n += 1;  /* normalize number (avoid -0) */
87  lua_assert(sizeof(a) <= sizeof(n));
88  memcpy(a, &n, sizeof(a));
89  for (i = 1; i < numints; i++) a[0] += a[i];
90  return hashmod(t, cast(lu_hash, a[0]));
91}
92
93
94
95/*
96** returns the `main' position of an element in a table (that is, the index
97** of its hash value)
98*/
99Node *luaH_mainposition (const Table *t, const TObject *key) {
100  switch (ttype(key)) {
101    case LUA_TNUMBER:
102      return hashnum(t, nvalue(key));
103    case LUA_TSTRING:
104      return hashstr(t, tsvalue(key));
105    case LUA_TBOOLEAN:
106      return hashboolean(t, bvalue(key));
107    case LUA_TLIGHTUSERDATA:
108      return hashpointer(t, pvalue(key));
109    default:
110      return hashpointer(t, gcvalue(key));
111  }
112}
113
114
115/*
116** returns the index for `key' if `key' is an appropriate key to live in
117** the array part of the table, -1 otherwise.
118*/
119static int arrayindex (const TObject *key) {
120  if (ttisnumber(key)) {
121    int k;
122    lua_number2int(k, (nvalue(key)));
123    if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k))
124      return k;
125  }
126  return -1;  /* `key' did not match some condition */
127}
128
129
130/*
131** returns the index of a `key' for table traversals. First goes all
132** elements in the array part, then elements in the hash part. The
133** beginning and end of a traversal are signalled by -1.
134*/
135static int luaH_index (lua_State *L, Table *t, StkId key) {
136  int i;
137  if (ttisnil(key)) return -1;  /* first iteration */
138  i = arrayindex(key);
139  if (0 <= i && i <= t->sizearray) {  /* is `key' inside array part? */
140    return i-1;  /* yes; that's the index (corrected to C) */
141  }
142  else {
143    const TObject *v = luaH_get(t, key);
144    if (v == &luaO_nilobject)
145      luaG_runerror(L, "invalid key for `next'");
146    i = cast(int, (cast(const lu_byte *, v) -
147                   cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node));
148    return i + t->sizearray;  /* hash elements are numbered after array ones */
149  }
150}
151
152
153int luaH_next (lua_State *L, Table *t, StkId key) {
154  int i = luaH_index(L, t, key);  /* find original element */
155  for (i++; i < t->sizearray; i++) {  /* try first array part */
156    if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
157      setnvalue(key, cast(lua_Number, i+1));
158      setobj2s(key+1, &t->array[i]);
159      return 1;
160    }
161  }
162  for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */
163    if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */
164      setobj2s(key, gkey(gnode(t, i)));
165      setobj2s(key+1, gval(gnode(t, i)));
166      return 1;
167    }
168  }
169  return 0;  /* no more elements */
170}
171
172
173/*
174** {=============================================================
175** Rehash
176** ==============================================================
177*/
178
179
180static void computesizes  (int nums[], int ntotal, int *narray, int *nhash) {
181  int i;
182  int a = nums[0];  /* number of elements smaller than 2^i */
183  int na = a;  /* number of elements to go to array part */
184  int n = (na == 0) ? -1 : 0;  /* (log of) optimal size for array part */
185  for (i = 1; a < *narray && *narray >= twoto(i-1); i++) {
186    if (nums[i] > 0) {
187      a += nums[i];
188      if (a >= twoto(i-1)) {  /* more than half elements in use? */
189        n = i;
190        na = a;
191      }
192    }
193  }
194  lua_assert(na <= *narray && *narray <= ntotal);
195  *nhash = ntotal - na;
196  *narray = (n == -1) ? 0 : twoto(n);
197  lua_assert(na <= *narray && na >= *narray/2);
198}
199
200
201static void numuse (const Table *t, int *narray, int *nhash) {
202  int nums[MAXBITS+1];
203  int i, lg;
204  int totaluse = 0;
205  /* count elements in array part */
206  for (i=0, lg=0; lg<=MAXBITS; lg++) {  /* for each slice [2^(lg-1) to 2^lg) */
207    int ttlg = twoto(lg);  /* 2^lg */
208    if (ttlg > t->sizearray) {
209      ttlg = t->sizearray;
210      if (i >= ttlg) break;
211    }
212    nums[lg] = 0;
213    for (; i<ttlg; i++) {
214      if (!ttisnil(&t->array[i])) {
215        nums[lg]++;
216        totaluse++;
217      }
218    }
219  }
220  for (; lg<=MAXBITS; lg++) nums[lg] = 0;  /* reset other counts */
221  *narray = totaluse;  /* all previous uses were in array part */
222  /* count elements in hash part */
223  i = sizenode(t);
224  while (i--) {
225    Node *n = &t->node[i];
226    if (!ttisnil(gval(n))) {
227      int k = arrayindex(gkey(n));
228      if (k >= 0) {  /* is `key' an appropriate array index? */
229        nums[luaO_log2(k-1)+1]++;  /* count as such */
230        (*narray)++;
231      }
232      totaluse++;
233    }
234  }
235  computesizes(nums, totaluse, narray, nhash);
236}
237
238
239static void setarrayvector (lua_State *L, Table *t, int size) {
240  int i;
241  luaM_reallocvector(L, t->array, t->sizearray, size, TObject);
242  for (i=t->sizearray; i<size; i++)
243     setnilvalue(&t->array[i]);
244  t->sizearray = size;
245}
246
247
248static void setnodevector (lua_State *L, Table *t, int lsize) {
249  int i;
250  int size = twoto(lsize);
251  if (lsize > MAXBITS)
252    luaG_runerror(L, "table overflow");
253  if (lsize == 0) {  /* no elements to hash part? */
254    t->node = G(L)->dummynode;  /* use common `dummynode' */
255    lua_assert(ttisnil(gkey(t->node)));  /* assert invariants: */
256    lua_assert(ttisnil(gval(t->node)));
257    lua_assert(t->node->next == NULL);  /* (`dummynode' must be empty) */
258  }
259  else {
260    t->node = luaM_newvector(L, size, Node);
261    for (i=0; i<size; i++) {
262      t->node[i].next = NULL;
263      setnilvalue(gkey(gnode(t, i)));
264      setnilvalue(gval(gnode(t, i)));
265    }
266  }
267  t->lsizenode = cast(lu_byte, lsize);
268  t->firstfree = gnode(t, size-1);  /* first free position to be used */
269}
270
271
272static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
273  int i;
274  int oldasize = t->sizearray;
275  int oldhsize = t->lsizenode;
276  Node *nold;
277  Node temp[1];
278  if (oldhsize)
279    nold = t->node;  /* save old hash ... */
280  else {  /* old hash is `dummynode' */
281    lua_assert(t->node == G(L)->dummynode);
282    temp[0] = t->node[0];  /* copy it to `temp' */
283    nold = temp;
284    setnilvalue(gkey(G(L)->dummynode));  /* restate invariant */
285    setnilvalue(gval(G(L)->dummynode));
286    lua_assert(G(L)->dummynode->next == NULL);
287  }
288  if (nasize > oldasize)  /* array part must grow? */
289    setarrayvector(L, t, nasize);
290  /* create new hash part with appropriate size */
291  setnodevector(L, t, nhsize); 
292  /* re-insert elements */
293  if (nasize < oldasize) {  /* array part must shrink? */
294    t->sizearray = nasize;
295    /* re-insert elements from vanishing slice */
296    for (i=nasize; i<oldasize; i++) {
297      if (!ttisnil(&t->array[i]))
298        setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]);
299    }
300    /* shrink array */
301    luaM_reallocvector(L, t->array, oldasize, nasize, TObject);
302  }
303  /* re-insert elements in hash part */
304  for (i = twoto(oldhsize) - 1; i >= 0; i--) {
305    Node *old = nold+i;
306    if (!ttisnil(gval(old)))
307      setobjt2t(luaH_set(L, t, gkey(old)), gval(old));
308  }
309  if (oldhsize)
310    luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */
311}
312
313
314static void rehash (lua_State *L, Table *t) {
315  int nasize, nhsize;
316  numuse(t, &nasize, &nhsize);  /* compute new sizes for array and hash parts */
317  resize(L, t, nasize, luaO_log2(nhsize)+1);
318}
319
320
321
322/*
323** }=============================================================
324*/
325
326
327Table *luaH_new (lua_State *L, int narray, int lnhash) {
328  Table *t = luaM_new(L, Table);
329  luaC_link(L, valtogco(t), LUA_TTABLE);
330  t->metatable = hvalue(defaultmeta(L));
331  t->flags = cast(lu_byte, ~0);
332  /* temporary values (kept only if some malloc fails) */
333  t->array = NULL;
334  t->sizearray = 0;
335  t->lsizenode = 0;
336  t->node = NULL;
337  setarrayvector(L, t, narray);
338  setnodevector(L, t, lnhash);
339  return t;
340}
341
342
343void luaH_free (lua_State *L, Table *t) {
344  if (t->lsizenode)
345    luaM_freearray(L, t->node, sizenode(t), Node);
346  luaM_freearray(L, t->array, t->sizearray, TObject);
347  luaM_freelem(L, t);
348}
349
350
351#if 0
352/*
353** try to remove an element from a hash table; cannot move any element
354** (because gc can call `remove' during a table traversal)
355*/
356void luaH_remove (Table *t, Node *e) {
357  Node *mp = luaH_mainposition(t, gkey(e));
358  if (e != mp) {  /* element not in its main position? */
359    while (mp->next != e) mp = mp->next;  /* find previous */
360    mp->next = e->next;  /* remove `e' from its list */
361  }
362  else {
363    if (e->next != NULL) ??
364  }
365  lua_assert(ttisnil(gval(node)));
366  setnilvalue(gkey(e));  /* clear node `e' */
367  e->next = NULL;
368}
369#endif
370
371
372/*
373** inserts a new key into a hash table; first, check whether key's main
374** position is free. If not, check whether colliding node is in its main
375** position or not: if it is not, move colliding node to an empty place and
376** put new key in its main position; otherwise (colliding node is in its main
377** position), new key goes to an empty position.
378*/
379static TObject *newkey (lua_State *L, Table *t, const TObject *key) {
380  TObject *val;
381  Node *mp = luaH_mainposition(t, key);
382  if (!ttisnil(gval(mp))) {  /* main position is not free? */
383    Node *othern = luaH_mainposition(t, gkey(mp));  /* `mp' of colliding node */
384    Node *n = t->firstfree;  /* get a free place */
385    if (othern != mp) {  /* is colliding node out of its main position? */
386      /* yes; move colliding node into free position */
387      while (othern->next != mp) othern = othern->next;  /* find previous */
388      othern->next = n;  /* redo the chain with `n' in place of `mp' */
389      *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
390      mp->next = NULL;  /* now `mp' is free */
391      setnilvalue(gval(mp));
392    }
393    else {  /* colliding node is in its own main position */
394      /* new node will go into free position */
395      n->next = mp->next;  /* chain new position */
396      mp->next = n;
397      mp = n;
398    }
399  }
400  setobj2t(gkey(mp), key);  /* write barrier */
401  lua_assert(ttisnil(gval(mp)));
402  for (;;) {  /* correct `firstfree' */
403    if (ttisnil(gkey(t->firstfree)))
404      return gval(mp);  /* OK; table still has a free place */
405    else if (t->firstfree == t->node) break;  /* cannot decrement from here */
406    else (t->firstfree)--;
407  }
408  /* no more free places; must create one */
409  setbvalue(gval(mp), 0);  /* avoid new key being removed */
410  rehash(L, t);  /* grow table */
411  val = cast(TObject *, luaH_get(t, key));  /* get new position */
412  lua_assert(ttisboolean(val));
413  setnilvalue(val);
414  return val;
415}
416
417
418/*
419** generic search function
420*/
421static const TObject *luaH_getany (Table *t, const TObject *key) {
422  if (ttisnil(key)) return &luaO_nilobject;
423  else {
424    Node *n = luaH_mainposition(t, key);
425    do {  /* check whether `key' is somewhere in the chain */
426      if (luaO_rawequalObj(gkey(n), key)) return gval(n);  /* that's it */
427      else n = n->next;
428    } while (n);
429    return &luaO_nilobject;
430  }
431}
432
433
434/*
435** search function for integers
436*/
437const TObject *luaH_getnum (Table *t, int key) {
438  if (1 <= key && key <= t->sizearray)
439    return &t->array[key-1];
440  else {
441    lua_Number nk = cast(lua_Number, key);
442    Node *n = hashnum(t, nk);
443    do {  /* check whether `key' is somewhere in the chain */
444      if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk)
445        return gval(n);  /* that's it */
446      else n = n->next;
447    } while (n);
448    return &luaO_nilobject;
449  }
450}
451
452
453/*
454** search function for strings
455*/
456const TObject *luaH_getstr (Table *t, TString *key) {
457  Node *n = hashstr(t, key);
458  do {  /* check whether `key' is somewhere in the chain */
459    if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key)
460      return gval(n);  /* that's it */
461    else n = n->next;
462  } while (n);
463  return &luaO_nilobject;
464}
465
466
467/*
468** main search function
469*/
470const TObject *luaH_get (Table *t, const TObject *key) {
471  switch (ttype(key)) {
472    case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
473    case LUA_TNUMBER: {
474      int k;
475      lua_number2int(k, (nvalue(key)));
476      if (cast(lua_Number, k) == nvalue(key))  /* is an integer index? */
477        return luaH_getnum(t, k);  /* use specialized version */
478      /* else go through */
479    }
480    default: return luaH_getany(t, key);
481  }
482}
483
484
485TObject *luaH_set (lua_State *L, Table *t, const TObject *key) {
486  const TObject *p = luaH_get(t, key);
487  t->flags = 0;
488  if (p != &luaO_nilobject)
489    return cast(TObject *, p);
490  else {
491    if (ttisnil(key)) luaG_runerror(L, "table index is nil");
492    else if (ttisnumber(key) && nvalue(key) != nvalue(key))
493      luaG_runerror(L, "table index is NaN");
494    return newkey(L, t, key);
495  }
496}
497
498
499TObject *luaH_setnum (lua_State *L, Table *t, int key) {
500  const TObject *p = luaH_getnum(t, key);
501  if (p != &luaO_nilobject)
502    return cast(TObject *, p);
503  else {
504    TObject k;
505    setnvalue(&k, cast(lua_Number, key));
506    return newkey(L, t, &k);
507  }
508}
509
Note: See TracBrowser for help on using the repository browser.