comparison src/hash.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 8eaf7971accc
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Hash tables.
2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Synched up with: Not in FSF. */
22
23 #ifdef emacs
24 #include <config.h>
25 #include "lisp.h"
26
27 #define NULL_ENTRY (LISP_TO_VOID (Qnil))
28
29 #else /* !emacs */
30
31 #define NULL_ENTRY ((void *) 1)
32
33 #endif /* !emacs */
34
35 #include <string.h>
36 #include "hash.h"
37 #include "elhash.h"
38
39 static CONST int
40 primes []={
41 13,
42 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631,
43 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013,
44 8419, 10103, 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361,
45 62851, 75431, 90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449,
46 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, 1674319,
47 2009191, 2411033, 2893249
48 };
49
50 /* strings code */
51
52 /* from base/generic-hash.cc, and hence from Dragon book, p436 */
53 unsigned long
54 string_hash (CONST void *xv)
55 {
56 unsigned int h = 0;
57 unsigned int g;
58 unsigned CONST char *x = (unsigned CONST char *) xv;
59
60 if (!x) return 0;
61
62 while (*x != 0)
63 {
64 h = (h << 4) + *x++;
65 if ((g = h & 0xf0000000) != 0)
66 h = (h ^ (g >> 24)) ^ g;
67 }
68
69 return h;
70 }
71
72 unsigned long
73 memory_hash (CONST void *xv, int size)
74 {
75 unsigned int h = 0;
76 unsigned int g;
77 unsigned CONST char *x = (unsigned CONST char *) xv;
78
79 if (!x) return 0;
80
81 while (size > 0)
82 {
83 h = (h << 4) + *x++;
84 if ((g = h & 0xf0000000) != 0)
85 h = (h ^ (g >> 24)) ^ g;
86 size--;
87 }
88
89 return h;
90 }
91
92 static int
93 string_eq (CONST void *st1v, CONST void *st2v)
94 {
95 CONST char *st1 = (CONST char *)st1v;
96 CONST char *st2 = (CONST char *)st2v;
97
98 if (!st1)
99 return (st2)?0:1;
100 else if (!st2)
101 return 0;
102 else
103 return !strcmp (st1, st2);
104 }
105
106
107 static unsigned int
108 prime_size (unsigned int size)
109 {
110 unsigned int i;
111 CONST int lim = countof (primes);
112 for (i = 0; i < lim; i++)
113 if (size <= primes [i]) return primes [i];
114 return primes [lim - 1];
115 }
116
117 static void rehash (hentry *harray, c_hashtable ht, unsigned int size);
118
119 #define KEYS_DIFFER_P(old, new, testfun) \
120 ((testfun)?(((old) == (new))?0:(!(testfun ((old), new)))):((old) != (new)))
121
122 CONST void *
123 gethash (CONST void *key, c_hashtable hash, CONST void **ret_value)
124 {
125 hentry *harray = hash->harray;
126 int (*test_function) (CONST void *, CONST void *) = hash->test_function;
127 unsigned int hsize = hash->size;
128 unsigned int hcode_initial =
129 (hash->hash_function)?(hash->hash_function(key)):((unsigned long) key);
130 unsigned int hcode = hcode_initial % hsize;
131 hentry *e = &harray [hcode];
132 CONST void *e_key = e->key;
133
134 if (!key)
135 {
136 *ret_value = hash->zero_entry;
137 return (void *) hash->zero_set;
138 }
139
140 if ((e_key)?
141 (KEYS_DIFFER_P (e_key, key, test_function)):
142 (e->contents == NULL_ENTRY))
143 {
144 unsigned int h2 = hsize - 2;
145 unsigned int incr = 1 + (hcode_initial % h2);
146 do
147 {
148 hcode = hcode + incr;
149 if (hcode >= hsize) hcode = hcode - hsize;
150 e = &harray [hcode];
151 e_key = e->key;
152 }
153 while ((e_key)?
154 (KEYS_DIFFER_P (e_key, key, test_function)):
155 (e->contents == NULL_ENTRY));
156 }
157
158 *ret_value = e->contents;
159 return e->key;
160 }
161
162 void
163 clrhash (c_hashtable hash)
164 {
165 memset (hash->harray, 0, sizeof (hentry) * hash->size);
166 hash->zero_entry = 0;
167 hash->zero_set = 0;
168 hash->fullness = 0;
169 }
170
171 void
172 free_hashtable (c_hashtable hash)
173 {
174 #ifdef emacs
175 if (!NILP (hash->elisp_table))
176 return;
177 #endif
178 xfree (hash->harray);
179 xfree (hash);
180 }
181
182 c_hashtable
183 make_hashtable (unsigned int hsize)
184 {
185 c_hashtable res = (c_hashtable) xmalloc (sizeof (struct _C_hashtable));
186 memset (res, 0, sizeof (struct _C_hashtable));
187 res->size = prime_size ((13 * hsize) / 10);
188 res->harray = (hentry *) xmalloc (sizeof (hentry) * res->size);
189 #ifdef emacs
190 res->elisp_table = Qnil;
191 #endif
192 clrhash (res);
193 return res;
194 }
195
196 c_hashtable
197 make_general_hashtable (unsigned int hsize,
198 unsigned long (*hash_function) (CONST void *),
199 int (*test_function) (CONST void *, CONST void *))
200 {
201 c_hashtable res = (c_hashtable) xmalloc (sizeof (struct _C_hashtable));
202 memset (res, 0, sizeof (struct _C_hashtable));
203 res->size = prime_size ((13 * hsize) / 10);
204 res->harray = (hentry *) xmalloc (sizeof (hentry) * res->size);
205 res->hash_function = hash_function;
206 res->test_function = test_function;
207 #ifdef emacs
208 res->elisp_table = Qnil;
209 #endif
210 clrhash (res);
211 return res;
212 }
213
214 c_hashtable
215 make_strings_hashtable (unsigned int hsize)
216 {
217 return make_general_hashtable (hsize, string_hash, string_eq);
218 }
219
220 #ifdef emacs
221 unsigned int
222 compute_harray_size (unsigned int hsize)
223 {
224 return prime_size ((13 * hsize) / 10);
225 }
226 #endif
227
228 void
229 copy_hash (c_hashtable dest, c_hashtable src)
230 {
231 #ifdef emacs
232 /* if these are not the same, then we are losing here */
233 if ((NILP (dest->elisp_table)) != (NILP (src->elisp_table)))
234 {
235 error ("Incompatible hashtable types to copy_hash.");
236 return;
237 }
238 #endif
239
240 if (dest->size != src->size)
241 {
242 #ifdef emacs
243 if (!NILP (dest->elisp_table))
244 elisp_hvector_free (dest->harray, dest->elisp_table);
245 else
246 #endif
247 xfree (dest->harray);
248
249 dest->size = src->size;
250 #ifdef emacs
251 if (!NILP (dest->elisp_table))
252 dest->harray =
253 (hentry *) elisp_hvector_malloc
254 (sizeof (hentry) * dest->size, dest->elisp_table);
255 else
256 #endif
257 dest->harray = (hentry *) xmalloc (sizeof (hentry) * dest->size);
258 }
259 dest->fullness = src->fullness;
260 dest->zero_entry = src->zero_entry;
261 dest->zero_set = src->zero_set;
262 dest->hash_function = src->hash_function;
263 dest->test_function = src->test_function;
264 memcpy (dest->harray, src->harray, sizeof (hentry) * dest->size);
265 }
266
267 static void
268 grow_hashtable (c_hashtable hash, unsigned int new_size)
269 {
270 unsigned int old_hsize = hash->size;
271 hentry *old_harray = hash->harray;
272 unsigned int new_hsize = prime_size (new_size);
273 hentry *new_harray;
274
275 #ifdef emacs
276 /* We test for Qzero to facilitate free-hook.c. That module creates
277 a hashtable very very early, at which point Qnil has not yet
278 been set and is thus all zeroes. Qzero is "automatically"
279 initialized at startup because its correct value is also all
280 zeroes. */
281 if (!NILP (hash->elisp_table) && !ZEROP (hash->elisp_table))
282 new_harray = (hentry *) elisp_hvector_malloc (sizeof (hentry) * new_hsize,
283 hash->elisp_table);
284 else
285 #endif
286 new_harray =
287 (hentry *) xmalloc (sizeof (hentry) * new_hsize);
288
289 hash->size = new_hsize;
290 hash->harray = new_harray;
291
292 /* do the rehash on the "grown" table */
293 {
294 long old_zero_set = hash->zero_set;
295 void *old_zero_entry = hash->zero_entry;
296 clrhash (hash);
297 hash->zero_set = old_zero_set;
298 hash->zero_entry = old_zero_entry;
299 rehash (old_harray, hash, old_hsize);
300 }
301
302 #ifdef emacs
303 if (!NILP (hash->elisp_table) && !ZEROP (hash->elisp_table))
304 elisp_hvector_free (old_harray, hash->elisp_table);
305 else
306 #endif
307 xfree (old_harray);
308 }
309
310 void
311 expand_hashtable (c_hashtable hash, unsigned int needed_size)
312 {
313 unsigned int hsize = hash->size;
314 int comfortable_size = (13 * needed_size) / 10;
315 if (hsize < comfortable_size)
316 grow_hashtable (hash, comfortable_size + 1);
317 }
318
319 void
320 puthash (CONST void *key, void *cont, c_hashtable hash)
321 {
322 unsigned int hsize = hash->size;
323 int (*test_function) (CONST void *, CONST void *) = hash->test_function;
324 unsigned int fullness = hash->fullness;
325 hentry *harray;
326 CONST void *e_key;
327 hentry *e;
328 unsigned int hcode_initial =
329 (hash->hash_function)?(hash->hash_function(key)):((unsigned long) key);
330 unsigned int hcode;
331 unsigned int incr = 0;
332 unsigned int h2;
333 CONST void *oldcontents;
334
335 if (!key)
336 {
337 hash->zero_entry = cont;
338 hash->zero_set = 1;
339 return;
340 }
341
342 if (hsize < (1 + ((13 * fullness) / 10)))
343 {
344 grow_hashtable (hash, hsize + 1);
345 hsize = hash->size;
346 fullness = hash->fullness;
347 }
348
349 harray= hash->harray;
350 h2 = hsize - 2;
351
352 hcode = hcode_initial % hsize;
353
354 e_key = harray [hcode].key;
355 if (e_key && (KEYS_DIFFER_P (e_key, key, test_function)))
356 {
357 h2 = hsize - 2;
358 incr = 1 + (hcode_initial % h2);
359 do
360 {
361 hcode = hcode + incr;
362 if (hcode >= hsize) hcode = hcode - hsize;
363 e_key = harray [hcode].key;
364 }
365 while (e_key && (KEYS_DIFFER_P (e_key, key, test_function)));
366 }
367 oldcontents = harray [hcode].contents;
368 harray [hcode].key = key;
369 harray [hcode].contents = cont;
370 /* if the entry that we used was a deleted entry,
371 check for a non deleted entry of the same key,
372 then delete it */
373 if (!e_key && (oldcontents == NULL_ENTRY))
374 {
375 if (!incr) incr = 1 + ((unsigned long) key % h2);
376
377 do
378 {
379 hcode = hcode + incr;
380 if (hcode >= hsize) hcode = hcode - hsize;
381 e = &harray [hcode];
382 e_key = e->key;
383 }
384 while ((e_key)?
385 (KEYS_DIFFER_P (e_key, key, test_function)):
386 (e->contents == NULL_ENTRY));
387
388 if (e_key)
389 {
390 e->key = 0;
391 e->contents = NULL_ENTRY;
392 }
393 }
394
395 /* only increment the fullness when we used up a new hentry */
396 if (!e_key || (KEYS_DIFFER_P (e_key, key, test_function)))
397 hash->fullness++;
398 }
399
400 static void
401 rehash (hentry *harray, c_hashtable hash, unsigned int size)
402 {
403 hentry *limit = harray + size;
404 hentry *e;
405 for (e = harray; e < limit; e++)
406 {
407 if (e->key)
408 puthash (e->key, e->contents, hash);
409 }
410 }
411
412 void
413 remhash (CONST void *key, c_hashtable hash)
414 {
415 hentry *harray = hash->harray;
416 int (*test_function) (CONST void*, CONST void*) = hash->test_function;
417 unsigned int hsize = hash->size;
418 unsigned int hcode_initial =
419 (hash->hash_function)?(hash->hash_function(key)):((unsigned long) key);
420 unsigned int hcode = hcode_initial % hsize;
421 hentry *e = &harray [hcode];
422 CONST void *e_key = e->key;
423
424 if (!key)
425 {
426 hash->zero_entry = 0;
427 hash->zero_set = 0;
428 return;
429 }
430
431 if ((e_key)?
432 (KEYS_DIFFER_P (e_key, key, test_function)):
433 (e->contents == NULL_ENTRY))
434 {
435 unsigned int h2 = hsize - 2;
436 unsigned int incr = 1 + (hcode_initial % h2);
437 do
438 {
439 hcode = hcode + incr;
440 if (hcode >= hsize) hcode = hcode - hsize;
441 e = &harray [hcode];
442 e_key = e->key;
443 }
444 while ((e_key)?
445 (KEYS_DIFFER_P (e_key, key, test_function)):
446 (e->contents == NULL_ENTRY));
447 }
448 if (e_key)
449 {
450 e->key = 0;
451 e->contents = NULL_ENTRY;
452 /* Note: you can't do fullness-- here, it breaks the world. */
453 }
454 }
455
456 void
457 maphash (maphash_function mf, c_hashtable hash, void *arg)
458 {
459 hentry *e;
460 hentry *limit;
461
462 if (hash->zero_set)
463 ((*mf) (0, hash->zero_entry, arg));
464
465 for (e = hash->harray, limit = e + hash->size; e < limit; e++)
466 {
467 if (e->key)
468 ((*mf) (e->key, e->contents, arg));
469 }
470 }
471
472 void
473 map_remhash (remhash_predicate predicate, c_hashtable hash, void *arg)
474 {
475 hentry *e;
476 hentry *limit;
477
478 if (hash->zero_set && ((*predicate) (0, hash->zero_entry, arg)))
479 {
480 hash->zero_set = 0;
481 hash->zero_entry = 0;
482 }
483
484 for (e = hash->harray, limit = e + hash->size; e < limit; e++)
485 if ((*predicate) (e->key, e->contents, arg))
486 {
487 e->key = 0;
488 e->contents = NULL_ENTRY;
489 }
490 }