Patch-ID: bash40-027
[bash.git] / hashlib.c
blobccde9b9f54dc444006969ad893461b260a75a79f
1 /* hashlib.c -- functions to manage and access hash tables for bash. */
3 /* Copyright (C) 1987,1989,1991,1995,1998,2001,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 #include "bashansi.h"
25 #if defined (HAVE_UNISTD_H)
26 # ifdef _MINIX
27 # include <sys/types.h>
28 # endif
29 # include <unistd.h>
30 #endif
32 #include <stdio.h>
34 #include "shell.h"
35 #include "hashlib.h"
37 /* Rely on properties of unsigned division (unsigned/int -> unsigned) and
38 don't discard the upper 32 bits of the value, if present. */
39 #define HASH_BUCKET(s, t, h) (((h) = hash_string (s)) & ((t)->nbuckets - 1))
41 static BUCKET_CONTENTS *copy_bucket_array __P((BUCKET_CONTENTS *, sh_string_func_t *));
43 /* Make a new hash table with BUCKETS number of buckets. Initialize
44 each slot in the table to NULL. */
45 HASH_TABLE *
46 hash_create (buckets)
47 int buckets;
49 HASH_TABLE *new_table;
50 register int i;
52 new_table = (HASH_TABLE *)xmalloc (sizeof (HASH_TABLE));
53 if (buckets == 0)
54 buckets = DEFAULT_HASH_BUCKETS;
56 new_table->bucket_array =
57 (BUCKET_CONTENTS **)xmalloc (buckets * sizeof (BUCKET_CONTENTS *));
58 new_table->nbuckets = buckets;
59 new_table->nentries = 0;
61 for (i = 0; i < buckets; i++)
62 new_table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
64 return (new_table);
67 int
68 hash_size (table)
69 HASH_TABLE *table;
71 return (HASH_ENTRIES(table));
74 static BUCKET_CONTENTS *
75 copy_bucket_array (ba, cpdata)
76 BUCKET_CONTENTS *ba;
77 sh_string_func_t *cpdata; /* data copy function */
79 BUCKET_CONTENTS *new_bucket, *n, *e;
81 if (ba == 0)
82 return ((BUCKET_CONTENTS *)0);
84 for (n = (BUCKET_CONTENTS *)0, e = ba; e; e = e->next)
86 if (n == 0)
88 new_bucket = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
89 n = new_bucket;
91 else
93 n->next = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
94 n = n->next;
97 n->key = savestring (e->key);
98 n->data = e->data ? (cpdata ? (*cpdata) (e->data) : savestring (e->data))
99 : NULL;
100 n->khash = e->khash;
101 n->times_found = e->times_found;
102 n->next = (BUCKET_CONTENTS *)NULL;
105 return new_bucket;
108 HASH_TABLE *
109 hash_copy (table, cpdata)
110 HASH_TABLE *table;
111 sh_string_func_t *cpdata;
113 HASH_TABLE *new_table;
114 int i;
116 if (table == 0)
117 return ((HASH_TABLE *)NULL);
119 new_table = hash_create (table->nbuckets);
121 for (i = 0; i < table->nbuckets; i++)
122 new_table->bucket_array[i] = copy_bucket_array (table->bucket_array[i], cpdata);
124 new_table->nentries = table->nentries;
125 return new_table;
128 /* The `khash' check below requires that strings that compare equally with
129 strcmp hash to the same value. */
130 unsigned int
131 hash_string (s)
132 const char *s;
134 register unsigned int i;
136 /* This is the best string hash function I found.
138 The magic is in the interesting relationship between the special prime
139 16777619 (2^24 + 403) and 2^32 and 2^8. */
141 for (i = 0; *s; s++)
143 i *= 16777619;
144 i ^= *s;
147 return i;
150 /* Return the location of the bucket which should contain the data
151 for STRING. TABLE is a pointer to a HASH_TABLE. */
154 hash_bucket (string, table)
155 const char *string;
156 HASH_TABLE *table;
158 unsigned int h;
160 return (HASH_BUCKET (string, table, h));
163 /* Return a pointer to the hashed item. If the HASH_CREATE flag is passed,
164 create a new hash table entry for STRING, otherwise return NULL. */
165 BUCKET_CONTENTS *
166 hash_search (string, table, flags)
167 const char *string;
168 HASH_TABLE *table;
169 int flags;
171 BUCKET_CONTENTS *list;
172 int bucket;
173 unsigned int hv;
175 if (table == 0 || ((flags & HASH_CREATE) == 0 && HASH_ENTRIES (table) == 0))
176 return (BUCKET_CONTENTS *)NULL;
178 bucket = HASH_BUCKET (string, table, hv);
180 for (list = table->bucket_array[bucket]; list; list = list->next)
182 if (hv == list->khash && STREQ (list->key, string))
184 list->times_found++;
185 return (list);
189 if (flags & HASH_CREATE)
191 list = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
192 list->next = table->bucket_array[bucket];
193 table->bucket_array[bucket] = list;
195 list->data = NULL;
196 list->key = (char *)string; /* XXX fix later */
197 list->khash = hv;
198 list->times_found = 0;
200 table->nentries++;
201 return (list);
204 return (BUCKET_CONTENTS *)NULL;
207 /* Remove the item specified by STRING from the hash table TABLE.
208 The item removed is returned, so you can free its contents. If
209 the item isn't in this table NULL is returned. */
210 BUCKET_CONTENTS *
211 hash_remove (string, table, flags)
212 const char *string;
213 HASH_TABLE *table;
214 int flags;
216 int bucket;
217 BUCKET_CONTENTS *prev, *temp;
218 unsigned int hv;
220 if (table == 0 || HASH_ENTRIES (table) == 0)
221 return (BUCKET_CONTENTS *)NULL;
223 bucket = HASH_BUCKET (string, table, hv);
224 prev = (BUCKET_CONTENTS *)NULL;
225 for (temp = table->bucket_array[bucket]; temp; temp = temp->next)
227 if (hv == temp->khash && STREQ (temp->key, string))
229 if (prev)
230 prev->next = temp->next;
231 else
232 table->bucket_array[bucket] = temp->next;
234 table->nentries--;
235 return (temp);
237 prev = temp;
239 return ((BUCKET_CONTENTS *) NULL);
242 /* Create an entry for STRING, in TABLE. If the entry already
243 exists, then return it (unless the HASH_NOSRCH flag is set). */
244 BUCKET_CONTENTS *
245 hash_insert (string, table, flags)
246 char *string;
247 HASH_TABLE *table;
248 int flags;
250 BUCKET_CONTENTS *item;
251 int bucket;
252 unsigned int hv;
254 if (table == 0)
255 table = hash_create (0);
257 item = (flags & HASH_NOSRCH) ? (BUCKET_CONTENTS *)NULL
258 : hash_search (string, table, 0);
260 if (item == 0)
262 bucket = HASH_BUCKET (string, table, hv);
264 item = (BUCKET_CONTENTS *)xmalloc (sizeof (BUCKET_CONTENTS));
265 item->next = table->bucket_array[bucket];
266 table->bucket_array[bucket] = item;
268 item->data = NULL;
269 item->key = string;
270 item->khash = hv;
271 item->times_found = 0;
273 table->nentries++;
276 return (item);
279 /* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it
280 is a function to call to dispose of a hash item's data. Otherwise,
281 free() is called. */
282 void
283 hash_flush (table, free_data)
284 HASH_TABLE *table;
285 sh_free_func_t *free_data;
287 int i;
288 register BUCKET_CONTENTS *bucket, *item;
290 if (table == 0 || HASH_ENTRIES (table) == 0)
291 return;
293 for (i = 0; i < table->nbuckets; i++)
295 bucket = table->bucket_array[i];
297 while (bucket)
299 item = bucket;
300 bucket = bucket->next;
302 if (free_data)
303 (*free_data) (item->data);
304 else
305 free (item->data);
306 free (item->key);
307 free (item);
309 table->bucket_array[i] = (BUCKET_CONTENTS *)NULL;
312 table->nentries = 0;
315 /* Free the hash table pointed to by TABLE. */
316 void
317 hash_dispose (table)
318 HASH_TABLE *table;
320 free (table->bucket_array);
321 free (table);
324 void
325 hash_walk (table, func)
326 HASH_TABLE *table;
327 hash_wfunc *func;
329 register int i;
330 BUCKET_CONTENTS *item;
332 if (table == 0 || HASH_ENTRIES (table) == 0)
333 return;
335 for (i = 0; i < table->nbuckets; i++)
337 for (item = hash_items (i, table); item; item = item->next)
338 if ((*func) (item) < 0)
339 return;
343 #if defined (DEBUG) || defined (TEST_HASHING)
344 void
345 hash_pstats (table, name)
346 HASH_TABLE *table;
347 char *name;
349 register int slot, bcount;
350 register BUCKET_CONTENTS *bc;
352 if (name == 0)
353 name = "unknown hash table";
355 fprintf (stderr, "%s: %d buckets; %d items\n", name, table->nbuckets, table->nentries);
357 /* Print out a count of how many strings hashed to each bucket, so we can
358 see how even the distribution is. */
359 for (slot = 0; slot < table->nbuckets; slot++)
361 bc = hash_items (slot, table);
363 fprintf (stderr, "\tslot %3d: ", slot);
364 for (bcount = 0; bc; bc = bc->next)
365 bcount++;
367 fprintf (stderr, "%d\n", bcount);
370 #endif
372 #ifdef TEST_HASHING
374 /* link with xmalloc.o and lib/malloc/libmalloc.a */
375 #undef NULL
376 #include <stdio.h>
378 #ifndef NULL
379 #define NULL 0
380 #endif
382 HASH_TABLE *table, *ntable;
384 int interrupt_immediately = 0;
387 signal_is_trapped (s)
388 int s;
390 return (0);
393 void
394 programming_error (const char *format, ...)
396 abort();
399 void
400 fatal_error (const char *format, ...)
402 abort();
405 main ()
407 char string[256];
408 int count = 0;
409 BUCKET_CONTENTS *tt;
411 table = hash_create (0);
413 for (;;)
415 char *temp_string;
416 if (fgets (string, sizeof (string), stdin) == 0)
417 break;
418 if (!*string)
419 break;
420 temp_string = savestring (string);
421 tt = hash_insert (temp_string, table, 0);
422 if (tt->times_found)
424 fprintf (stderr, "You have already added item `%s'\n", string);
425 free (temp_string);
427 else
429 count++;
433 hash_pstats (table, "hash test");
435 ntable = hash_copy (table, (sh_string_func_t *)NULL);
436 hash_flush (table, (sh_free_func_t *)NULL);
437 hash_pstats (ntable, "hash copy test");
439 exit (0);
442 #endif /* TEST_HASHING */