]> sjero.net Git - wget/blob - src/hash.c
[svn] A bunch of new features:
[wget] / src / hash.c
1 /* Hash tables.
2    Copyright (C) 2000 Free Software Foundation, Inc.
3
4 This file is part of Wget.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #include "wget.h"
28 #include "utils.h"
29
30 #include "hash.h"
31
32 #ifdef STANDALONE
33 # define xmalloc malloc
34 # define xrealloc realloc
35 #endif
36
37 /* This file implements simple hash tables based on linear probing.
38    The hash table stores key-value pairs in a contiguous array.  Both
39    key and value are void pointers that the hash and test functions
40    know how to handle.
41
42    Although Knuth & co. recommend double hashing over linear probing,
43    we use the latter because it accesses array elements sequentially
44    in case of a collision, yielding in better cache behaviour and
45    ultimately in better speed.  To avoid collision problems with
46    linear probing, we make sure that the table grows as soon as the
47    fullness/size ratio exceeds 75%.  */
48
49 struct ht_pair {
50   void *key;
51   void *value;
52 };
53
54 struct hash_table {
55   unsigned long (*hash_function) (const void *);
56   int (*test_function) (const void *, const void *);
57
58   int size;                     /* size of the array */
59   int fullness;                 /* number of non-empty fields */
60   int count;                    /* number of non-empty, non-deleted
61                                    fields. */
62
63   struct ht_pair *pairs;
64 };
65
66 #define ENTRY_DELETED ((void *)0xdeadbeef)
67
68 #define DELETED_ENTRY_P(ptr) ((ptr) == ENTRY_DELETED)
69 #define EMPTY_ENTRY_P(ptr)   ((ptr) == NULL)
70
71 /* Find a prime near, but greather than or equal to SIZE. */
72
73 int
74 prime_size (int size)
75 {
76   static const unsigned long primes [] = {
77     19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031,
78     1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783,
79     19219, 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941,
80     204047, 265271, 344857, 448321, 582821, 757693, 985003, 1280519,
81     1664681, 2164111, 2813353, 3657361, 4754591, 6180989, 8035301,
82     10445899, 13579681, 17653589, 22949669, 29834603, 38784989,
83     50420551, 65546729, 85210757, 110774011, 144006217, 187208107,
84     243370577, 316381771, 411296309, 534685237, 695090819, 903618083,
85     1174703521, 1527114613, 1985248999, 2580823717UL, 3355070839UL
86   };
87   int i;
88   for (i = 0; i < ARRAY_SIZE (primes); i++)
89     if (primes[i] >= size)
90       return primes[i];
91   /* huh? */
92   return size;
93 }
94
95 /* Create a hash table of INITIAL_SIZE with hash function
96    HASH_FUNCTION and test function TEST_FUNCTION.  If you wish to
97    start out with a "small" table which will be regrown as needed,
98    specify 0 as INITIAL_SIZE.  */
99
100 struct hash_table *
101 hash_table_new (int initial_size,
102                 unsigned long (*hash_function) (const void *),
103                 int (*test_function) (const void *, const void *))
104 {
105   struct hash_table *ht
106     = (struct hash_table *)xmalloc (sizeof (struct hash_table));
107   ht->hash_function = hash_function;
108   ht->test_function = test_function;
109   ht->size = prime_size (initial_size);
110   ht->fullness = 0;
111   ht->count    = 0;
112   ht->pairs = xmalloc (ht->size * sizeof (struct ht_pair));
113   memset (ht->pairs, '\0', ht->size * sizeof (struct ht_pair));
114   return ht;
115 }
116
117 /* Free the data associated with hash table HT. */
118
119 void
120 hash_table_destroy (struct hash_table *ht)
121 {
122   free (ht->pairs);
123   free (ht);
124 }
125
126 /* Get the value that corresponds to the key KEY in the hash table HT.
127    If no value is found, return NULL.  Note that NULL is a legal value
128    for value; if you are storing NULLs in your hash table, you can use
129    hash_table_exists to be sure that a (possibly NULL) value exists in
130    the table.  */
131
132 void *
133 hash_table_get (struct hash_table *ht, const void *key)
134 {
135   int location = ht->hash_function (key) % ht->size;
136   while (1)
137     {
138       struct ht_pair *the_pair = ht->pairs + location;
139       if (EMPTY_ENTRY_P (the_pair->key))
140         return NULL;
141       else if (DELETED_ENTRY_P (the_pair->key)
142                || !ht->test_function (key, the_pair->key))
143         {
144           ++location;
145           if (location == ht->size)
146             location = 0;
147         }
148       else
149         return the_pair->value;
150     }
151 }
152
153 /* Return 1 if KEY exists in HT, 0 otherwise. */
154
155 int
156 hash_table_exists (struct hash_table *ht, const void *key)
157 {
158   int location = ht->hash_function (key) % ht->size;
159   while (1)
160     {
161       struct ht_pair *the_pair = ht->pairs + location;
162       if (EMPTY_ENTRY_P (the_pair->key))
163         return 0;
164       else if (DELETED_ENTRY_P (the_pair->key)
165                || !ht->test_function (key, the_pair->key))
166         {
167           ++location;
168           if (location == ht->size)
169             location = 0;
170         }
171       else
172         return 1;
173     }
174 }
175
176 #define MAX(i, j) (((i) >= (j)) ? (i) : (j))
177
178 /* Grow hash table HT as necessary, and rehash all the key-value
179    pairs.  */
180
181 static void
182 grow_hash_table (struct hash_table *ht)
183 {
184   int i;
185   struct ht_pair *old_pairs = ht->pairs;
186   int old_count = ht->count;    /* for assert() below */
187   int old_size = ht->size;
188
189   /* Normally, the idea is to double ht->size (and round it to next
190      prime) on each regrow:
191
192          ht->size = prime_size (ht->size * 2);
193
194      But it is possible that the table has large fullness because of
195      the many deleted entries.  If that is the case, we don't want to
196      blindly grow the table; we just want to rehash it.  For that
197      reason, we use ht->count as the relevant parameter.  MAX is used
198      only because we don't want to actually shrink the table.  (But
199      maybe that's wrong.)  */
200
201   int needed_size = prime_size (ht->count * 2);
202   ht->size = MAX (old_size, needed_size);
203
204   ht->pairs = xmalloc (ht->size * sizeof (struct ht_pair));
205   memset (ht->pairs, '\0', ht->size * sizeof (struct ht_pair));
206
207   /* Need to reset these two; hash_table_put will reinitialize them.  */
208   ht->fullness = 0;
209   ht->count    = 0;
210   for (i = 0; i < old_size; i++)
211     {
212       struct ht_pair *the_pair = old_pairs + i;
213       if (!EMPTY_ENTRY_P (the_pair->key)
214           && !DELETED_ENTRY_P (the_pair->key))
215         hash_table_put (ht, the_pair->key, the_pair->value);
216     }
217   assert (ht->count == old_count);
218   free (old_pairs);
219 }
220
221 /* Put VALUE in the hash table HT under the key KEY.  This regrows the
222    table if necessary.  */
223
224 void
225 hash_table_put (struct hash_table *ht, const void *key, void *value)
226 {
227   int location = ht->hash_function (key) % ht->size;
228   while (1)
229     {
230       struct ht_pair *the_pair = ht->pairs + location;
231       if (EMPTY_ENTRY_P (the_pair->key))
232         {
233           ++ht->fullness;
234           ++ht->count;
235         just_insert:
236           the_pair->key = (void *)key; /* const? */
237           the_pair->value = value;
238           break;
239         }
240       else if (DELETED_ENTRY_P (the_pair->key))
241         {
242           /* We're replacing a deleteed entry, so ht->count gets
243              increased, but ht->fullness remains unchanged.  */
244           ++ht->count;
245           goto just_insert;
246         }
247       else if (ht->test_function (key, the_pair->key))
248         {
249           /* We're replacing an existing entry, so ht->count and
250              ht->fullness remain unchanged.  */
251           goto just_insert;
252         }
253       else
254         {
255           ++location;
256           if (location == ht->size)
257             location = 0;
258         }
259     }
260   if (ht->fullness * 4 > ht->size * 3)
261     /* When fullness exceeds 75% of size, regrow the table. */
262     grow_hash_table (ht);
263 }
264
265 /* Remove KEY from HT. */
266
267 int
268 hash_table_remove (struct hash_table *ht, const void *key)
269 {
270   int location = ht->hash_function (key) % ht->size;
271   while (1)
272     {
273       struct ht_pair *the_pair = ht->pairs + location;
274       if (EMPTY_ENTRY_P (the_pair->key))
275         return 0;
276       else if (DELETED_ENTRY_P (the_pair->key)
277                || !ht->test_function (key, the_pair->key))
278         {
279           ++location;
280           if (location == ht->size)
281             location = 0;
282         }
283       else
284         {
285           /* We don't really remove an entry from the hash table: we
286              just mark it as deleted.  This is because there may be
287              other entries located after this entry whose hash number
288              points to a location before this entry.  (Example: keys
289              A, B and C have the same hash.  If you were to really
290              *delete* B from the table, C could no longer be found.)
291
292              As an optimization, it might be worthwhile to check
293              whether the immediately preceding entry is empty and, if
294              so, really delete the pair (set it to empty and decrease
295              the fullness along with the count).  I *think* it should
296              be safe.  */
297           the_pair->key = ENTRY_DELETED;
298           --ht->count;
299           return 1;
300         }
301     }
302 }
303
304 void
305 hash_table_clear (struct hash_table *ht)
306 {
307   memset (ht->pairs, '\0', ht->size * sizeof (struct ht_pair));
308   ht->fullness = 0;
309   ht->count    = 0;
310 }
311
312 void
313 hash_table_map (struct hash_table *ht,
314                 int (*mapfun) (void *, void *, void *),
315                 void *closure)
316 {
317   int i;
318   for (i = 0; i < ht->size; i++)
319     {
320       struct ht_pair *the_pair = ht->pairs + i;
321       if (!EMPTY_ENTRY_P (the_pair->key)
322           && !DELETED_ENTRY_P (the_pair->key))
323         if (mapfun (the_pair->key, the_pair->value, closure))
324           return;
325     }
326 }
327 \f
328 /* Support for hash tables whose keys are strings.  */
329
330 /* supposedly from the Dragon Book P436. */
331 unsigned long
332 string_hash (const void *sv)
333 {
334   unsigned int h = 0;
335   unsigned const char *x = (unsigned const char *) sv;
336
337   while (*x)
338     {
339       unsigned int g;
340       h = (h << 4) + *x++;
341       if ((g = h & 0xf0000000) != 0)
342         h = (h ^ (g >> 24)) ^ g;
343     }
344
345   return h;
346 }
347
348 int
349 string_cmp (const void *s1, const void *s2)
350 {
351   return !strcmp ((const char *)s1, (const char *)s2);
352 }
353
354 struct hash_table *
355 make_string_hash_table (int initial_size)
356 {
357   return hash_table_new (initial_size, string_hash, string_cmp);
358 }
359
360 \f
361 #ifdef STANDALONE
362
363 #include <stdio.h>
364 #include <string.h>
365
366 int
367 print_hash_table_mapper (const void *key, void *value, void *count)
368 {
369   ++*(int *)count;
370   printf ("%s: %s\n", (const char *)key, (char *)value);
371   return 0;
372 }
373
374 void
375 print_hash (struct hash_table *sht)
376 {
377   int debug_count = 0;
378   hash_table_map (sht, print_hash_table_mapper, &debug_count);
379   assert (debug_count == sht->count);
380 }
381
382 int
383 main (void)
384 {
385   struct hash_table *ht = make_string_hash_table (0);
386   char line[80];
387   while ((fgets (line, sizeof (line), stdin)))
388     {
389       int len = strlen (line);
390       if (len <= 1)
391         continue;
392       line[--len] = '\0';
393       hash_table_put (ht, strdup (line), "here I am!");
394       if (len % 2)
395         hash_table_remove (ht, line);
396     }
397   print_hash (ht);
398 #if 0
399   printf ("%d %d %d\n", ht->count, ht->fullness, ht->size);
400 #endif
401   return 0;
402 }
403 #endif