summaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/ltable.c b/ltable.c
new file mode 100644
index 00000000..6279d936
--- /dev/null
+++ b/ltable.c
@@ -0,0 +1,218 @@
1/*
2** $Id: ltable.c,v 1.1 1997/08/14 20:19:10 roberto Exp roberto $
3** Lua tables (hash)
4** See Copyright Notice in lua.h
5*/
6
7#include <stdlib.h>
8
9#include "lauxlib.h"
10#include "lmem.h"
11#include "lobject.h"
12#include "ltable.h"
13#include "lua.h"
14
15
16#define nuse(t) ((t)->nuse)
17#define nodevector(t) ((t)->node)
18#define val(n) (&(n)->val)
19
20
21#define REHASH_LIMIT 0.70 /* avoid more than this % full */
22
23#define TagDefault LUA_T_ARRAY;
24
25
26Hash *luaH_root = NULL;
27
28
29
30static long int hashindex (TObject *ref)
31{
32 long int h;
33 switch (ttype(ref)) {
34 case LUA_T_NUMBER:
35 h = (long int)nvalue(ref);
36 break;
37 case LUA_T_STRING: case LUA_T_USERDATA:
38 h = (IntPoint)tsvalue(ref);
39 break;
40 case LUA_T_FUNCTION:
41 h = (IntPoint)clvalue(ref);
42 break;
43 case LUA_T_CFUNCTION:
44 h = (IntPoint)fvalue(ref);
45 break;
46 case LUA_T_ARRAY:
47 h = (IntPoint)avalue(ref);
48 break;
49 default:
50 lua_error("unexpected type to index table");
51 h = 0; /* UNREACHEABLE */
52 }
53 return (h >= 0 ? h : -(h+1));
54}
55
56
57static int present (Hash *t, TObject *key)
58{
59 int tsize = nhash(t);
60 long int h = hashindex(key);
61 int h1 = h%tsize;
62 TObject *rf = ref(node(t, h1));
63 if (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)) {
64 int h2 = h%(tsize-2) + 1;
65 do {
66 h1 = (h1+h2)%tsize;
67 rf = ref(node(t, h1));
68 } while (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf));
69 }
70 return h1;
71}
72
73
74/*
75** Alloc a vector node
76*/
77static Node *hashnodecreate (int nhash)
78{
79 int i;
80 Node *v = luaM_newvector (nhash, Node);
81 for (i=0; i<nhash; i++)
82 ttype(ref(&v[i])) = LUA_T_NIL;
83 return v;
84}
85
86/*
87** Delete a hash
88*/
89static void hashdelete (Hash *t)
90{
91 luaM_free (nodevector(t));
92 luaM_free(t);
93}
94
95
96void luaH_free (Hash *frees)
97{
98 while (frees) {
99 Hash *next = (Hash *)frees->head.next;
100 hashdelete(frees);
101 frees = next;
102 }
103}
104
105
106static void inserttable (Hash *table)
107{
108 ++luaO_nentities;
109 table->head.next = (GCnode *)luaH_root;
110 luaH_root = table;
111 table->head.marked = 0;
112}
113
114Hash *luaH_new (int nhash)
115{
116 Hash *t = luaM_new(Hash);
117 nhash = luaO_redimension((int)((float)nhash/REHASH_LIMIT));
118 nodevector(t) = hashnodecreate(nhash);
119 nhash(t) = nhash;
120 nuse(t) = 0;
121 t->htag = TagDefault;
122 inserttable(t);
123 return t;
124}
125
126
127/*
128** Rehash:
129** Check if table has deleted slots. It it has, it does not need to
130** grow, since rehash will reuse them.
131*/
132static int emptyslots (Hash *t)
133{
134 int i;
135 for (i=nhash(t)-1; i>=0; i--) {
136 Node *n = node(t, i);
137 if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) == LUA_T_NIL)
138 return 1;
139 }
140 return 0;
141}
142
143static void rehash (Hash *t)
144{
145 int nold = nhash(t);
146 Node *vold = nodevector(t);
147 int i;
148 if (!emptyslots(t))
149 nhash(t) = luaO_redimension(nhash(t));
150 nodevector(t) = hashnodecreate(nhash(t));
151 for (i=0; i<nold; i++) {
152 Node *n = vold+i;
153 if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL)
154 *node(t, present(t, ref(n))) = *n; /* copy old node to luaM_new hash */
155 }
156 luaM_free(vold);
157}
158
159/*
160** If the hash node is present, return its pointer, otherwise return
161** null.
162*/
163TObject *luaH_get (Hash *t, TObject *ref)
164{
165 int h = present(t, ref);
166 if (ttype(ref(node(t, h))) != LUA_T_NIL) return val(node(t, h));
167 else return NULL;
168}
169
170
171/*
172** If the hash node is present, return its pointer, otherwise create a luaM_new
173** node for the given reference and also return its pointer.
174*/
175TObject *luaH_set (Hash *t, TObject *ref)
176{
177 Node *n = node(t, present(t, ref));
178 if (ttype(ref(n)) == LUA_T_NIL) {
179 nuse(t)++;
180 if ((float)nuse(t) > (float)nhash(t)*REHASH_LIMIT) {
181 rehash(t);
182 n = node(t, present(t, ref));
183 }
184 *ref(n) = *ref;
185 ttype(val(n)) = LUA_T_NIL;
186 }
187 return (val(n));
188}
189
190
191static Node *hashnext (Hash *t, int i)
192{
193 Node *n;
194 int tsize = nhash(t);
195 if (i >= tsize)
196 return NULL;
197 n = node(t, i);
198 while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) {
199 if (++i >= tsize)
200 return NULL;
201 n = node(t, i);
202 }
203 return node(t, i);
204}
205
206Node *luaH_next (TObject *o, TObject *r)
207{
208 Hash *t = avalue(o);
209 if (ttype(r) == LUA_T_NIL)
210 return hashnext(t, 0);
211 else {
212 int i = present(t, r);
213 Node *n = node(t, i);
214 luaL_arg_check(ttype(ref(n))!=LUA_T_NIL && ttype(val(n))!=LUA_T_NIL,
215 2, "key not found");
216 return hashnext(t, i+1);
217 }
218}