]>
git.ipfire.org Git - thirdparty/bash.git/blob - hashlib.c
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/>.
25 #if defined (HAVE_UNISTD_H)
27 # include <sys/types.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. */
49 HASH_TABLE
*new_table
;
52 new_table
= (HASH_TABLE
*)xmalloc (sizeof (HASH_TABLE
));
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
;
71 return (HASH_ENTRIES(table
));
74 static BUCKET_CONTENTS
*
75 copy_bucket_array (ba
, cpdata
)
77 sh_string_func_t
*cpdata
; /* data copy function */
79 BUCKET_CONTENTS
*new_bucket
, *n
, *e
;
82 return ((BUCKET_CONTENTS
*)0);
84 for (n
= (BUCKET_CONTENTS
*)0, e
= ba
; e
; e
= e
->next
)
88 new_bucket
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
93 n
->next
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
97 n
->key
= savestring (e
->key
);
98 n
->data
= e
->data
? (cpdata
? (*cpdata
) (e
->data
) : savestring (e
->data
))
101 n
->times_found
= e
->times_found
;
102 n
->next
= (BUCKET_CONTENTS
*)NULL
;
109 hash_copy (table
, cpdata
)
111 sh_string_func_t
*cpdata
;
113 HASH_TABLE
*new_table
;
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
;
128 /* This is the best 32-bit string hash function I found. It's one of the
129 Fowler-Noll-Vo family (FNV-1).
131 The magic is in the interesting relationship between the special prime
132 16777619 (2^24 + 403) and 2^32 and 2^8. */
134 #define FNV_OFFSET 2166136261
135 #define FNV_PRIME 16777619
137 /* If you want to use 64 bits, use
138 FNV_OFFSET 14695981039346656037
139 FNV_PRIMT 1099511628211
142 /* The `khash' check below requires that strings that compare equally with
143 strcmp hash to the same value. */
148 register unsigned int i
;
150 for (i
= FNV_OFFSET
; *s
; s
++)
159 /* Return the location of the bucket which should contain the data
160 for STRING. TABLE is a pointer to a HASH_TABLE. */
163 hash_bucket (string
, table
)
169 return (HASH_BUCKET (string
, table
, h
));
172 /* Return a pointer to the hashed item. If the HASH_CREATE flag is passed,
173 create a new hash table entry for STRING, otherwise return NULL. */
175 hash_search (string
, table
, flags
)
180 BUCKET_CONTENTS
*list
;
184 if (table
== 0 || ((flags
& HASH_CREATE
) == 0 && HASH_ENTRIES (table
) == 0))
185 return (BUCKET_CONTENTS
*)NULL
;
187 bucket
= HASH_BUCKET (string
, table
, hv
);
189 for (list
= table
->bucket_array
? table
->bucket_array
[bucket
] : 0; list
; list
= list
->next
)
191 /* This is the comparison function */
192 if (hv
== list
->khash
&& STREQ (list
->key
, string
))
199 if (flags
& HASH_CREATE
)
201 list
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
202 list
->next
= table
->bucket_array
[bucket
];
203 table
->bucket_array
[bucket
] = list
;
206 list
->key
= (char *)string
; /* XXX fix later */
208 list
->times_found
= 0;
214 return (BUCKET_CONTENTS
*)NULL
;
217 /* Remove the item specified by STRING from the hash table TABLE.
218 The item removed is returned, so you can free its contents. If
219 the item isn't in this table NULL is returned. */
221 hash_remove (string
, table
, flags
)
227 BUCKET_CONTENTS
*prev
, *temp
;
230 if (table
== 0 || HASH_ENTRIES (table
) == 0)
231 return (BUCKET_CONTENTS
*)NULL
;
233 bucket
= HASH_BUCKET (string
, table
, hv
);
234 prev
= (BUCKET_CONTENTS
*)NULL
;
235 for (temp
= table
->bucket_array
[bucket
]; temp
; temp
= temp
->next
)
237 if (hv
== temp
->khash
&& STREQ (temp
->key
, string
))
240 prev
->next
= temp
->next
;
242 table
->bucket_array
[bucket
] = temp
->next
;
249 return ((BUCKET_CONTENTS
*) NULL
);
252 /* Create an entry for STRING, in TABLE. If the entry already
253 exists, then return it (unless the HASH_NOSRCH flag is set). */
255 hash_insert (string
, table
, flags
)
260 BUCKET_CONTENTS
*item
;
265 table
= hash_create (0);
267 item
= (flags
& HASH_NOSRCH
) ? (BUCKET_CONTENTS
*)NULL
268 : hash_search (string
, table
, 0);
272 bucket
= HASH_BUCKET (string
, table
, hv
);
274 item
= (BUCKET_CONTENTS
*)xmalloc (sizeof (BUCKET_CONTENTS
));
275 item
->next
= table
->bucket_array
[bucket
];
276 table
->bucket_array
[bucket
] = item
;
281 item
->times_found
= 0;
289 /* Remove and discard all entries in TABLE. If FREE_DATA is non-null, it
290 is a function to call to dispose of a hash item's data. Otherwise,
293 hash_flush (table
, free_data
)
295 sh_free_func_t
*free_data
;
298 register BUCKET_CONTENTS
*bucket
, *item
;
300 if (table
== 0 || HASH_ENTRIES (table
) == 0)
303 for (i
= 0; i
< table
->nbuckets
; i
++)
305 bucket
= table
->bucket_array
[i
];
310 bucket
= bucket
->next
;
313 (*free_data
) (item
->data
);
319 table
->bucket_array
[i
] = (BUCKET_CONTENTS
*)NULL
;
325 /* Free the hash table pointed to by TABLE. */
330 free (table
->bucket_array
);
335 hash_walk (table
, func
)
340 BUCKET_CONTENTS
*item
;
342 if (table
== 0 || HASH_ENTRIES (table
) == 0)
345 for (i
= 0; i
< table
->nbuckets
; i
++)
347 for (item
= hash_items (i
, table
); item
; item
= item
->next
)
348 if ((*func
) (item
) < 0)
353 #if defined (DEBUG) || defined (TEST_HASHING)
355 hash_pstats (table
, name
)
359 register int slot
, bcount
;
360 register BUCKET_CONTENTS
*bc
;
363 name
= "unknown hash table";
365 fprintf (stderr
, "%s: %d buckets; %d items\n", name
, table
->nbuckets
, table
->nentries
);
367 /* Print out a count of how many strings hashed to each bucket, so we can
368 see how even the distribution is. */
369 for (slot
= 0; slot
< table
->nbuckets
; slot
++)
371 bc
= hash_items (slot
, table
);
373 fprintf (stderr
, "\tslot %3d: ", slot
);
374 for (bcount
= 0; bc
; bc
= bc
->next
)
377 fprintf (stderr
, "%d\n", bcount
);
384 /* link with xmalloc.o and lib/malloc/libmalloc.a */
392 HASH_TABLE
*table
, *ntable
;
394 int interrupt_immediately
= 0;
397 signal_is_trapped (s
)
404 programming_error (const char *format
, ...)
410 fatal_error (const char *format
, ...)
416 internal_warning (const char *format
, ...)
426 #if defined (TEST_NBUCKETS)
427 table
= hash_create (TEST_NBUCKETS
);
429 table
= hash_create (0);
435 if (fgets (string
, sizeof (string
), stdin
) == 0)
439 temp_string
= savestring (string
);
440 tt
= hash_insert (temp_string
, table
, 0);
443 fprintf (stderr
, "You have already added item `%s'\n", string
);
452 hash_pstats (table
, "hash test");
454 ntable
= hash_copy (table
, (sh_string_func_t
*)NULL
);
455 hash_flush (table
, (sh_free_func_t
*)NULL
);
456 hash_pstats (ntable
, "hash copy test");
461 #endif /* TEST_HASHING */