aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-05-08 17:43:30 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>1997-05-08 17:43:30 -0300
commit9747f3c87a205d9aa914a650686d6dc4accde1d9 (patch)
treecf6b5c523c496995a333bfd490b9bf23a663360c
parent12d9731a49530c4190142da3621f8508a629ca88 (diff)
downloadlua-9747f3c87a205d9aa914a650686d6dc4accde1d9.tar.gz
lua-9747f3c87a205d9aa914a650686d6dc4accde1d9.tar.bz2
lua-9747f3c87a205d9aa914a650686d6dc4accde1d9.zip
double hashing + tables do not grow if there are empty slots
-rw-r--r--hash.c177
1 files changed, 94 insertions, 83 deletions
diff --git a/hash.c b/hash.c
index a794d14f..9c543955 100644
--- a/hash.c
+++ b/hash.c
@@ -3,7 +3,7 @@
3** hash manager for lua 3** hash manager for lua
4*/ 4*/
5 5
6char *rcs_hash="$Id: hash.c,v 2.40 1997/04/04 15:35:37 roberto Exp roberto $"; 6char *rcs_hash="$Id: hash.c,v 2.41 1997/04/06 14:08:08 roberto Exp roberto $";
7 7
8 8
9#include "luamem.h" 9#include "luamem.h"
@@ -33,7 +33,7 @@ static Hash *listhead = NULL;
33 33
34/* hash dimensions values */ 34/* hash dimensions values */
35static Long dimensions[] = 35static Long dimensions[] =
36 {3L, 5L, 7L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L, 36 {5L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L,
37 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L, 37 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L,
38 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT}; 38 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT};
39 39
@@ -49,7 +49,26 @@ int luaI_redimension (int nhash)
49 return 0; /* to avoid warnings */ 49 return 0; /* to avoid warnings */
50} 50}
51 51
52static int hashindex (Hash *t, TObject *ref) /* hash function */ 52
53int lua_equalObj (TObject *t1, TObject *t2)
54{
55 if (ttype(t1) != ttype(t2)) return 0;
56 switch (ttype(t1))
57 {
58 case LUA_T_NIL: return 1;
59 case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2);
60 case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2);
61 case LUA_T_ARRAY: return avalue(t1) == avalue(t2);
62 case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf;
63 case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2);
64 default:
65 lua_error("internal error in `lua_equalObj'");
66 return 0; /* UNREACHEABLE */
67 }
68}
69
70
71static long int hashindex (TObject *ref)
53{ 72{
54 long int h; 73 long int h;
55 switch (ttype(ref)) { 74 switch (ttype(ref)) {
@@ -68,36 +87,24 @@ static int hashindex (Hash *t, TObject *ref) /* hash function */
68 h = 0; /* UNREACHEABLE */ 87 h = 0; /* UNREACHEABLE */
69 } 88 }
70 if (h < 0) h = -h; 89 if (h < 0) h = -h;
71 return h%nhash(t); /* make it a valid index */ 90 return h;
72} 91}
73 92
74int lua_equalObj (TObject *t1, TObject *t2) 93
94static int present (Hash *t, TObject *key)
75{ 95{
76 if (ttype(t1) != ttype(t2)) return 0; 96 long int h = hashindex(key);
77 switch (ttype(t1)) 97 int tsize = nhash(t);
78 { 98 int h1 = h%tsize;
79 case LUA_T_NIL: return 1; 99 TObject *rf = ref(node(t, h1));
80 case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); 100 if (ttype(rf) != LUA_T_NIL && !lua_equalObj(key, rf)) {
81 case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2); 101 int h2 = h%(tsize-2) + 1;
82 case LUA_T_ARRAY: return avalue(t1) == avalue(t2); 102 do {
83 case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf; 103 h1 = (h1+h2)%tsize;
84 case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2); 104 rf = ref(node(t, h1));
85 default: 105 } while (ttype(rf) != LUA_T_NIL && !lua_equalObj(key, rf));
86 lua_error("internal error in `lua_equalObj'");
87 return 0; /* UNREACHEABLE */
88 } 106 }
89} 107 return h1;
90
91static int present (Hash *t, TObject *ref)
92{
93 int h = hashindex(t, ref);
94 while (ttype(ref(node(t, h))) != LUA_T_NIL)
95 {
96 if (lua_equalObj(ref, ref(node(t, h))))
97 return h;
98 h = (h+1) % nhash(t);
99 }
100 return h;
101} 108}
102 109
103 110
@@ -221,22 +228,35 @@ Hash *lua_createarray (int nhash)
221 228
222 229
223/* 230/*
224** Re-hash 231** Rehash:
232** Check if table has deleted slots. It it has, it does not need to
233** grow, since rehash will reuse them.
225*/ 234*/
235static int emptyslots (Hash *t)
236{
237 int i;
238 for (i=nhash(t)-1; i>=0; i--) {
239 Node *n = node(t, i);
240 if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) == LUA_T_NIL)
241 return 1;
242 }
243 return 0;
244}
245
226static void rehash (Hash *t) 246static void rehash (Hash *t)
227{ 247{
228 int i; 248 int nold = nhash(t);
229 int nold = nhash(t); 249 Node *vold = nodevector(t);
230 Node *vold = nodevector(t); 250 int i;
231 nhash(t) = luaI_redimension(nhash(t)); 251 if (!emptyslots(t))
232 nodevector(t) = hashnodecreate(nhash(t)); 252 nhash(t) = luaI_redimension(nhash(t));
233 for (i=0; i<nold; i++) 253 nodevector(t) = hashnodecreate(nhash(t));
234 { 254 for (i=0; i<nold; i++) {
235 Node *n = vold+i; 255 Node *n = vold+i;
236 if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL) 256 if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL)
237 *node(t, present(t, ref(n))) = *n; /* copy old node to new hahs */ 257 *node(t, present(t, ref(n))) = *n; /* copy old node to new hash */
238 } 258 }
239 luaI_free(vold); 259 luaI_free(vold);
240} 260}
241 261
242/* 262/*
@@ -257,23 +277,17 @@ TObject *lua_hashget (Hash *t, TObject *ref)
257*/ 277*/
258TObject *lua_hashdefine (Hash *t, TObject *ref) 278TObject *lua_hashdefine (Hash *t, TObject *ref)
259{ 279{
260 int h; 280 Node *n = node(t, present(t, ref));
261 Node *n; 281 if (ttype(ref(n)) == LUA_T_NIL) {
262 h = present(t, ref); 282 nuse(t)++;
263 n = node(t, h); 283 if ((float)nuse(t) > (float)nhash(t)*REHASH_LIMIT) {
264 if (ttype(ref(n)) == LUA_T_NIL) 284 rehash(t);
265 { 285 n = node(t, present(t, ref));
266 nuse(t)++; 286 }
267 if ((float)nuse(t) > (float)nhash(t)*REHASH_LIMIT) 287 *ref(n) = *ref;
268 { 288 ttype(val(n)) = LUA_T_NIL;
269 rehash(t);
270 h = present(t, ref);
271 n = node(t, h);
272 } 289 }
273 *ref(n) = *ref; 290 return (val(n));
274 ttype(val(n)) = LUA_T_NIL;
275 }
276 return (val(n));
277} 291}
278 292
279 293
@@ -285,33 +299,30 @@ TObject *lua_hashdefine (Hash *t, TObject *ref)
285*/ 299*/
286static void hashnext (Hash *t, int i) 300static void hashnext (Hash *t, int i)
287{ 301{
288 if (i >= nhash(t)) 302 Node *n;
289 return; 303 int tsize = nhash(t);
290 while (ttype(ref(node(t,i))) == LUA_T_NIL || 304 if (i >= tsize)
291 ttype(val(node(t,i))) == LUA_T_NIL) 305 return;
292 { 306 n = node(t, i);
293 if (++i >= nhash(t)) 307 while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) {
294 return; 308 if (++i >= tsize)
295 } 309 return;
296 luaI_pushobject(ref(node(t,i))); 310 n = node(t, i);
297 luaI_pushobject(val(node(t,i))); 311 }
312 luaI_pushobject(ref(node(t,i)));
313 luaI_pushobject(val(node(t,i)));
298} 314}
299 315
300void lua_next (void) 316void lua_next (void)
301{ 317{
302 Hash *t; 318 Hash *t;
303 lua_Object o = lua_getparam(1); 319 lua_Object o = lua_getparam(1);
304 lua_Object r = lua_getparam(2); 320 lua_Object r = lua_getparam(2);
305 luaL_arg_check(lua_istable(o), 1, "table expected"); 321 luaL_arg_check(lua_istable(o), 1, "table expected");
306 luaL_arg_check(r != LUA_NOOBJECT, 2, "value expected"); 322 luaL_arg_check(r != LUA_NOOBJECT, 2, "value expected");
307 t = avalue(luaI_Address(o)); 323 t = avalue(luaI_Address(o));
308 if (lua_isnil(r)) 324 if (lua_isnil(r))
309 { 325 hashnext(t, 0);
310 hashnext(t, 0); 326 else
311 } 327 hashnext(t, present(t, luaI_Address(r))+1);
312 else
313 {
314 int h = present (t, luaI_Address(r));
315 hashnext(t, h+1);
316 }
317} 328}