aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaldemar Celes <celes@tecgraf.puc-rio.br>1994-08-09 08:24:45 -0300
committerWaldemar Celes <celes@tecgraf.puc-rio.br>1994-08-09 08:24:45 -0300
commitb28da81cfe371f602474f75c0c4f706772eed92a (patch)
tree545597f252950306763dea54cd371851d2a11b1d
parent41fd23287aae60354c264be8f1807bccd937fbf1 (diff)
downloadlua-b28da81cfe371f602474f75c0c4f706772eed92a.tar.gz
lua-b28da81cfe371f602474f75c0c4f706772eed92a.tar.bz2
lua-b28da81cfe371f602474f75c0c4f706772eed92a.zip
Alteracao do hash, trocando tratamento de colisao por lista
pela estrategia de re-hash. Foi feito uma avaliacao da funcao de hash, e constatado sua eficiencia com uma media de 4 acessos no hash ate' 70% ocupado.
-rw-r--r--hash.c304
-rw-r--r--hash.h6
2 files changed, 152 insertions, 158 deletions
diff --git a/hash.c b/hash.c
index 143c6f55..cec4c2e4 100644
--- a/hash.c
+++ b/hash.c
@@ -1,10 +1,9 @@
1/* 1/*
2** hash.c 2** hash.c
3** hash manager for lua 3** hash manager for lua
4** Luiz Henrique de Figueiredo - 17 Aug 90
5*/ 4*/
6 5
7char *rcs_hash="$Id: hash.c,v 2.2 1994/07/19 21:27:18 celes Exp celes $"; 6char *rcs_hash="$Id: hash.c,v 2.3 1994/08/05 19:25:09 celes Exp celes $";
8 7
9#include <string.h> 8#include <string.h>
10#include <stdlib.h> 9#include <stdlib.h>
@@ -17,19 +16,21 @@ char *rcs_hash="$Id: hash.c,v 2.2 1994/07/19 21:27:18 celes Exp celes $";
17#include "table.h" 16#include "table.h"
18#include "lua.h" 17#include "lua.h"
19 18
20#define streq(s1,s2) (strcmp(s1,s2)==0) 19#define streq(s1,s2) (*(s1) == *(s2) && strcmp(s1,s2)==0)
21#define strneq(s1,s2) (strcmp(s1,s2)!=0)
22 20
23#define new(s) ((s *)malloc(sizeof(s))) 21#define new(s) ((s *)malloc(sizeof(s)))
24#define newvector(n,s) ((s *)calloc(n,sizeof(s))) 22#define newvector(n,s) ((s *)calloc(n,sizeof(s)))
25 23
26#define nhash(t) ((t)->nhash) 24#define nhash(t) ((t)->nhash)
27#define nodelist(t) ((t)->list) 25#define nuse(t) ((t)->nuse)
28#define list(t,i) ((t)->list[i])
29#define markarray(t) ((t)->mark) 26#define markarray(t) ((t)->mark)
30#define ref_tag(n) (tag(&(n)->ref)) 27#define nodevector(t) ((t)->node)
31#define ref_nvalue(n) (nvalue(&(n)->ref)) 28#define node(t,i) (&(t)->node[i])
32#define ref_svalue(n) (svalue(&(n)->ref)) 29#define ref(n) (&(n)->ref)
30#define val(n) (&(n)->val)
31
32
33#define REHASH_LIMIT 0.70 /* avoid more than this % full */
33 34
34 35
35typedef struct ArrayList 36typedef struct ArrayList
@@ -40,68 +41,97 @@ typedef struct ArrayList
40 41
41static ArrayList *listhead = NULL; 42static ArrayList *listhead = NULL;
42 43
43static int head (Hash *t, Object *ref) /* hash function */ 44
45
46/* hash dimensions values */
47static int dimensions[] =
48 {7, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 0};
49static int redimension (int nhash)
44{ 50{
45 if (tag(ref) == T_NUMBER) return (((int)nvalue(ref))%nhash(t)); 51 int i;
46 else if (tag(ref) == T_STRING) 52 for (i=0; dimensions[i]!=0; i++)
47 {
48 int h;
49 char *name = svalue(ref);
50 for (h=0; *name!=0; name++) /* interpret name as binary number */
51 {
52 h <<= 8;
53 h += (unsigned char) *name; /* avoid sign extension */
54 h %= nhash(t); /* make it a valid index */
55 }
56 return h;
57 }
58 else
59 { 53 {
60 lua_reportbug ("unexpected type to index table"); 54 if (dimensions[i] > nhash)
61 return -1; 55 return dimensions[i];
62 } 56 }
57 return nhash*2+1;
63} 58}
64 59
65static Node *present(Hash *t, Object *ref, int h) 60static int index (Hash *t, Object *ref) /* hash function */
66{ 61{
67 Node *n=NULL, *p; 62 switch (tag(ref))
68 if (tag(ref) == T_NUMBER)
69 { 63 {
70 for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next) 64 case T_NUMBER:
71 if (ref_tag(n) == T_NUMBER && nvalue(ref) == ref_nvalue(n)) break; 65 return (((int)nvalue(ref))%nhash(t));
72 } 66 case T_STRING:
73 else if (tag(ref) == T_STRING) 67 {
68 int h;
69 char *name = svalue(ref);
70 for (h=0; *name!=0; name++) /* interpret name as binary number */
71 {
72 h <<= 8;
73 h += (unsigned char) *name; /* avoid sign extension */
74 h %= nhash(t); /* make it a valid index */
75 }
76 return h;
77 }
78 case T_FUNCTION:
79 return (((int)bvalue(ref))%nhash(t));
80 case T_CFUNCTION:
81 return (((int)fvalue(ref))%nhash(t));
82 case T_ARRAY:
83 return (((int)avalue(ref))%nhash(t));
84 case T_USERDATA:
85 return (((int)uvalue(ref))%nhash(t));
86 default:
87 lua_reportbug ("unexpected type to index table");
88 return -1;
89 }
90}
91
92static int present (Hash *t, Object *ref)
93{
94 int h = index(t, ref);
95 if (h < 0) return h;
96 while (tag(ref(node(t, h))) != T_NIL)
74 { 97 {
75 for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next) 98 NCOLISSIONS++;
76 if (ref_tag(n) == T_STRING && streq(svalue(ref),ref_svalue(n))) break; 99 if (tag(ref) == T_NUMBER && tag(ref(node(t, h))) == T_NUMBER &&
100 nvalue(ref) == nvalue(ref(node(t, h)))
101 ) return h;
102 if (tag(ref) == T_STRING && tag(ref(node(t, h))) == T_STRING &&
103 streq(svalue(ref),svalue(ref(node(t, h))))
104 ) return h;
105 if (tag(ref) == tag(ref(node(t, h))) &&
106 uvalue(ref) == uvalue(ref(node(t, h))) /* all others are pointers */
107 ) return h;
108 h = (h+1) % nhash(t);
77 } 109 }
78 if (n==NULL) /* name not present */ 110 return h;
79 return NULL;
80#if 0
81 if (p!=NULL) /* name present but not first */
82 {
83 p->next=n->next; /* move-to-front self-organization */
84 n->next=list(t,h);
85 list(t,h)=n;
86 }
87#endif
88 return n;
89} 111}
90 112
91static void freelist (Node *n) 113
114/*
115** Alloc a vector node
116*/
117static Node *hashnodecreate (int nhash)
92{ 118{
93 while (n) 119 int i;
120 Node *v = newvector (nhash, Node);
121 if (v == NULL)
94 { 122 {
95 Node *next = n->next; 123 lua_error ("not enough memory");
96 free (n); 124 return NULL;
97 n = next;
98 } 125 }
126 for (i=0; i<nhash; i++)
127 tag(ref(&v[i])) = T_NIL;
128 return v;
99} 129}
100 130
101/* 131/*
102** Create a new hash. Return the hash pointer or NULL on error. 132** Create a new hash. Return the hash pointer or NULL on error.
103*/ 133*/
104static Hash *hashcreate (unsigned int nhash) 134static Hash *hashcreate (int nhash)
105{ 135{
106 Hash *t = new (Hash); 136 Hash *t = new (Hash);
107 if (t == NULL) 137 if (t == NULL)
@@ -109,27 +139,25 @@ static Hash *hashcreate (unsigned int nhash)
109 lua_error ("not enough memory"); 139 lua_error ("not enough memory");
110 return NULL; 140 return NULL;
111 } 141 }
142 nhash = redimension(nhash);
143
144 nodevector(t) = hashnodecreate(nhash);
145 if (nodevector(t) == NULL)
146 return NULL;
147
112 nhash(t) = nhash; 148 nhash(t) = nhash;
149 nuse(t) = 0;
113 markarray(t) = 0; 150 markarray(t) = 0;
114 nodelist(t) = newvector (nhash, Node*);
115 if (nodelist(t) == NULL)
116 {
117 lua_error ("not enough memory");
118 return NULL;
119 }
120 return t; 151 return t;
121} 152}
122 153
123/* 154/*
124** Delete a hash 155** Delete a hash
125*/ 156*/
126static void hashdelete (Hash *h) 157static void hashdelete (Hash *t)
127{ 158{
128 int i; 159 free (nodevector(t));
129 for (i=0; i<nhash(h); i++) 160 free(t);
130 freelist (list(h,i));
131 free (nodelist(h));
132 free(h);
133} 161}
134 162
135 163
@@ -144,8 +172,8 @@ void lua_hashmark (Hash *h)
144 markarray(h) = 1; 172 markarray(h) = 1;
145 for (i=0; i<nhash(h); i++) 173 for (i=0; i<nhash(h); i++)
146 { 174 {
147 Node *n; 175 Node *n = node(h,i);
148 for (n = list(h,i); n != NULL; n = n->next) 176 if (tag(ref(n)) != T_NIL)
149 { 177 {
150 lua_markobject(&n->ref); 178 lua_markobject(&n->ref);
151 lua_markobject(&n->val); 179 lua_markobject(&n->val);
@@ -213,18 +241,35 @@ Hash *lua_createarray (int nhash)
213 241
214 242
215/* 243/*
244** Re-hash
245*/
246static void rehash (Hash *t)
247{
248 int i;
249 int nold = nhash(t);
250 Node *vold = nodevector(t);
251 nhash(t) = redimension(nhash(t));
252 nodevector(t) = hashnodecreate(nhash(t));
253 for (i=0; i<nold; i++)
254 {
255 Node *n = vold+i;
256 if (tag(ref(n)) != T_NIL && tag(val(n)) != T_NIL)
257 *node(t, present(t, ref(n))) = *n; /* copy old node to new hahs */
258 }
259 free(vold);
260}
261
262/*
216** If the hash node is present, return its pointer, otherwise return a 263** If the hash node is present, return its pointer, otherwise return a
217** static nil object 264** static nil object
218*/ 265*/
219Object *lua_hashget (Hash *t, Object *ref) 266Object *lua_hashget (Hash *t, Object *ref)
220{ 267{
221 static Object nil_obj = {T_NIL, {NULL}}; 268 static Object nil_obj = {T_NIL, {NULL}};
222 Node *n; 269 int h = present(t, ref);
223 int h = head (t, ref);
224 if (h < 0) return NULL; 270 if (h < 0) return NULL;
225 n = present(t, ref, h); 271 if (tag(ref(node(t, h))) == T_NIL) return &nil_obj;
226 if (n == NULL) return &nil_obj; 272 else return val(node(t, h));
227 else return &n->val;
228} 273}
229 274
230/* 275/*
@@ -236,24 +281,22 @@ Object *lua_hashdefine (Hash *t, Object *ref)
236{ 281{
237 int h; 282 int h;
238 Node *n; 283 Node *n;
239 h = head (t, ref); 284 h = present(t, ref);
240 if (h < 0) return NULL; 285 if (h < 0) return NULL;
241 286 n = node(t, h);
242 n = present(t, ref, h); 287 if (tag(ref(n)) == T_NIL)
243 if (n == NULL)
244 { 288 {
245 n = new(Node); 289 nuse(t)++;
246 if (n == NULL) 290 if (nuse(t) > nhash(t)*REHASH_LIMIT)
247 { 291 {
248 lua_error ("not enough memory"); 292 rehash(t);
249 return NULL; 293 h = present(t, ref);
294 n = node(t, h);
250 } 295 }
251 n->ref = *ref; 296 *ref(n) = *ref;
252 tag(&n->val) = T_NIL; 297 tag(val(n)) = T_NIL;
253 n->next = list(t,h); /* link node to head of list */
254 list(t,h) = n;
255 } 298 }
256 return (&n->val); 299 return (val(n));
257} 300}
258 301
259 302
@@ -263,41 +306,28 @@ Object *lua_hashdefine (Hash *t, Object *ref)
263** in the hash. 306** in the hash.
264** This function pushs the element value and its reference to the stack. 307** This function pushs the element value and its reference to the stack.
265*/ 308*/
266static void firstnode (Hash *a, int h) 309static void hashnext (Hash *t, int i)
267{ 310{
268 if (h < nhash(a)) 311 if (i >= nhash(t))
269 { 312 {
270 int i; 313 lua_pushnil(); lua_pushnil();
271 for (i=h; i<nhash(a); i++) 314 return;
315 }
316 while (tag(ref(node(t,i))) == T_NIL || tag(val(node(t,i))) == T_NIL)
317 {
318 if (++i >= nhash(t))
272 { 319 {
273 if (list(a,i) != NULL) 320 lua_pushnil(); lua_pushnil();
274 { 321 return;
275 if (tag(&list(a,i)->val) != T_NIL)
276 {
277 lua_pushobject (&list(a,i)->ref);
278 lua_pushobject (&list(a,i)->val);
279 return;
280 }
281 else
282 {
283 Node *next = list(a,i)->next;
284 while (next != NULL && tag(&next->val) == T_NIL) next = next->next;
285 if (next != NULL)
286 {
287 lua_pushobject (&next->ref);
288 lua_pushobject (&next->val);
289 return;
290 }
291 }
292 }
293 } 322 }
294 } 323 }
295 lua_pushnil(); 324 lua_pushobject(ref(node(t,i)));
296 lua_pushnil(); 325 lua_pushobject(val(node(t,i)));
297} 326}
327
298void lua_next (void) 328void lua_next (void)
299{ 329{
300 Hash *a; 330 Hash *t;
301 Object *o = lua_getparam (1); 331 Object *o = lua_getparam (1);
302 Object *r = lua_getparam (2); 332 Object *r = lua_getparam (2);
303 if (o == NULL || r == NULL) 333 if (o == NULL || r == NULL)
@@ -306,55 +336,19 @@ void lua_next (void)
306 { lua_error ("too many arguments to function `next'"); return; } 336 { lua_error ("too many arguments to function `next'"); return; }
307 if (tag(o) != T_ARRAY) 337 if (tag(o) != T_ARRAY)
308 { lua_error ("first argument of function `next' is not a table"); return; } 338 { lua_error ("first argument of function `next' is not a table"); return; }
309 a = avalue(o); 339
340 t = avalue(o);
310 if (tag(r) == T_NIL) 341 if (tag(r) == T_NIL)
311 { 342 {
312 firstnode (a, 0); 343 hashnext(t, 0);
313 return;
314 } 344 }
315 else 345 else
316 { 346 {
317 int h = head (a, r); 347 int h = present (t, r);
318 if (h >= 0) 348 if (h >= 0)
319 { 349 hashnext(t, h+1);
320 Node *n = list(a,h); 350 else
321 while (n) 351 lua_error ("error in function 'next': reference not found");
322 {
323 if (memcmp(&n->ref,r,sizeof(Object)) == 0)
324 {
325 if (n->next == NULL)
326 {
327 firstnode (a, h+1);
328 return;
329 }
330 else if (tag(&n->next->val) != T_NIL)
331 {
332 lua_pushobject (&n->next->ref);
333 lua_pushobject (&n->next->val);
334 return;
335 }
336 else
337 {
338 Node *next = n->next->next;
339 while (next != NULL && tag(&next->val) == T_NIL) next = next->next;
340 if (next == NULL)
341 {
342 firstnode (a, h+1);
343 return;
344 }
345 else
346 {
347 lua_pushobject (&next->ref);
348 lua_pushobject (&next->val);
349 }
350 return;
351 }
352 }
353 n = n->next;
354 }
355 if (n == NULL)
356 lua_error ("error in function 'next': reference not found");
357 }
358 } 352 }
359} 353}
360 354
diff --git a/hash.h b/hash.h
index f296ec8d..38576527 100644
--- a/hash.h
+++ b/hash.h
@@ -2,7 +2,7 @@
2** hash.h 2** hash.h
3** hash manager for lua 3** hash manager for lua
4** Luiz Henrique de Figueiredo - 17 Aug 90 4** Luiz Henrique de Figueiredo - 17 Aug 90
5** $Id: hash.h,v 2.1 1994/04/20 22:07:57 celes Exp celes $ 5** $Id: hash.h,v 2.2 1994/08/05 19:25:09 celes Exp celes $
6*/ 6*/
7 7
8#ifndef hash_h 8#ifndef hash_h
@@ -12,14 +12,14 @@ typedef struct node
12{ 12{
13 Object ref; 13 Object ref;
14 Object val; 14 Object val;
15 struct node *next;
16} Node; 15} Node;
17 16
18typedef struct Hash 17typedef struct Hash
19{ 18{
20 char mark; 19 char mark;
21 unsigned int nhash; 20 unsigned int nhash;
22 Node **list; 21 unsigned int nuse;
22 Node *node;
23} Hash; 23} Hash;
24 24
25 25