diff options
Diffstat (limited to 'ltable.c')
-rw-r--r-- | ltable.c | 218 |
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 | |||
26 | Hash *luaH_root = NULL; | ||
27 | |||
28 | |||
29 | |||
30 | static 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 | |||
57 | static 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 | */ | ||
77 | static 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 | */ | ||
89 | static void hashdelete (Hash *t) | ||
90 | { | ||
91 | luaM_free (nodevector(t)); | ||
92 | luaM_free(t); | ||
93 | } | ||
94 | |||
95 | |||
96 | void 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 | |||
106 | static 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 | |||
114 | Hash *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 | */ | ||
132 | static 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 | |||
143 | static 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 | */ | ||
163 | TObject *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 | */ | ||
175 | TObject *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 | |||
191 | static 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 | |||
206 | Node *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 | } | ||