diff options
author | Waldemar Celes <celes@tecgraf.puc-rio.br> | 1994-08-09 08:24:45 -0300 |
---|---|---|
committer | Waldemar Celes <celes@tecgraf.puc-rio.br> | 1994-08-09 08:24:45 -0300 |
commit | b28da81cfe371f602474f75c0c4f706772eed92a (patch) | |
tree | 545597f252950306763dea54cd371851d2a11b1d | |
parent | 41fd23287aae60354c264be8f1807bccd937fbf1 (diff) | |
download | lua-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.c | 304 | ||||
-rw-r--r-- | hash.h | 6 |
2 files changed, 152 insertions, 158 deletions
@@ -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 | ||
7 | char *rcs_hash="$Id: hash.c,v 2.2 1994/07/19 21:27:18 celes Exp celes $"; | 6 | char *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 | ||
35 | typedef struct ArrayList | 36 | typedef struct ArrayList |
@@ -40,68 +41,97 @@ typedef struct ArrayList | |||
40 | 41 | ||
41 | static ArrayList *listhead = NULL; | 42 | static ArrayList *listhead = NULL; |
42 | 43 | ||
43 | static int head (Hash *t, Object *ref) /* hash function */ | 44 | |
45 | |||
46 | /* hash dimensions values */ | ||
47 | static int dimensions[] = | ||
48 | {7, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 0}; | ||
49 | static 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 | ||
65 | static Node *present(Hash *t, Object *ref, int h) | 60 | static 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 | |||
92 | static 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 | ||
91 | static void freelist (Node *n) | 113 | |
114 | /* | ||
115 | ** Alloc a vector node | ||
116 | */ | ||
117 | static 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 | */ |
104 | static Hash *hashcreate (unsigned int nhash) | 134 | static 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 | */ |
126 | static void hashdelete (Hash *h) | 157 | static 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 | */ | ||
246 | static 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 | */ |
219 | Object *lua_hashget (Hash *t, Object *ref) | 266 | Object *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 | */ |
266 | static void firstnode (Hash *a, int h) | 309 | static 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 | |||
298 | void lua_next (void) | 328 | void 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 | ||
@@ -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 | ||
18 | typedef struct Hash | 17 | typedef 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 | ||