1 /*****************************************************************************
2 * $Id: hash.c,v 1.1.10.2 2008/12/18 18:02:13 johann Exp $
3 *****************************************************************************
4 * Copyright (C) 2003-2005 The Regents of the University of California.
5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
6 * Written by Chris Dunlap <cdunlap@llnl.gov>.
8 * This file is from LSD-Tools, the LLNL Software Development Toolbox.
10 * This is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * You should have received a copy of the GNU General Public License;
21 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
22 * Fifth Floor, Boston, MA 02110-1301 USA.
23 *****************************************************************************
24 * Refer to "hash.h" for documentation on public functions.
25 *****************************************************************************/
30 #endif /* HAVE_CONFIG_H */
41 /*****************************************************************************
43 *****************************************************************************/
45 #define HASH_ALLOC 1024
46 #define HASH_DEF_SIZE 1213
47 #define HASH_MAGIC 0xDEADBEEF
50 /*****************************************************************************
52 *****************************************************************************/
55 struct hash_node *next; /* next node in list */
56 void *data; /* ptr to hashed item */
57 const void *hkey; /* ptr to hashed item's key */
61 int count; /* number of items in hash table */
62 int size; /* num slots allocated in hash table */
63 struct hash_node **table; /* hash table array of node ptrs */
64 hash_cmp_f cmp_f; /* key comparison function */
65 hash_del_f del_f; /* item deletion function */
66 hash_key_f key_f; /* key hash function */
68 pthread_mutex_t mutex; /* mutex to protect access to hash */
69 #endif /* WITH_PTHREADS */
71 unsigned int magic; /* sentinel for asserting validity */
76 /*****************************************************************************
78 *****************************************************************************/
80 static struct hash_node * hash_node_alloc (void);
82 static void hash_node_free (struct hash_node *node);
85 /*****************************************************************************
87 *****************************************************************************/
90 static struct hash_node *hash_free_list = NULL;
94 static pthread_mutex_t hash_free_lock = PTHREAD_MUTEX_INITIALIZER;
95 #endif /* WITH_PTHREADS */
98 /*****************************************************************************
100 *****************************************************************************/
102 #ifdef WITH_LSD_FATAL_ERROR_FUNC
103 # undef lsd_fatal_error
104 extern void lsd_fatal_error (char *file, int line, char *mesg);
105 #else /* !WITH_LSD_FATAL_ERROR_FUNC */
106 # ifndef lsd_fatal_error
107 # define lsd_fatal_error(file, line, mesg) (abort ())
108 # endif /* !lsd_fatal_error */
109 #endif /* !WITH_LSD_FATAL_ERROR_FUNC */
111 #ifdef WITH_LSD_NOMEM_ERROR_FUNC
112 # undef lsd_nomem_error
113 extern void * lsd_nomem_error (char *file, int line, char *mesg);
114 #else /* !WITH_LSD_NOMEM_ERROR_FUNC */
115 # ifndef lsd_nomem_error
116 # define lsd_nomem_error(file, line, mesg) (NULL)
117 # endif /* !lsd_nomem_error */
118 #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
121 /*****************************************************************************
123 *****************************************************************************/
126 hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f)
130 if (!cmp_f || !key_f) {
135 size = HASH_DEF_SIZE;
137 if (!(h = malloc (sizeof (*h)))) {
138 return (lsd_nomem_error (__FILE__, __LINE__, "hash_create"));
140 if (!(h->table = calloc (size, sizeof (struct hash_node *)))) {
142 return (lsd_nomem_error (__FILE__, __LINE__, "hash_create"));
149 lsd_mutex_init (&h->mutex);
150 assert (h->magic = HASH_MAGIC); /* set magic via assert abuse */
156 hash_destroy (hash_t h)
159 struct hash_node *p, *q;
165 lsd_mutex_lock (&h->mutex);
166 assert (h->magic == HASH_MAGIC);
167 for (i = 0; i < h->size; i++) {
168 for (p = h->table[i]; p != NULL; p = q) {
175 assert (h->magic = ~HASH_MAGIC); /* clear magic via assert abuse */
176 lsd_mutex_unlock (&h->mutex);
177 lsd_mutex_destroy (&h->mutex);
185 hash_is_empty (hash_t h)
193 lsd_mutex_lock (&h->mutex);
194 assert (h->magic == HASH_MAGIC);
196 lsd_mutex_unlock (&h->mutex);
202 hash_count (hash_t h)
210 lsd_mutex_lock (&h->mutex);
211 assert (h->magic == HASH_MAGIC);
213 lsd_mutex_unlock (&h->mutex);
219 hash_find (hash_t h, const void *key)
230 lsd_mutex_lock (&h->mutex);
231 assert (h->magic == HASH_MAGIC);
232 slot = h->key_f (key) % h->size;
233 for (p = h->table[slot]; p != NULL; p = p->next) {
234 if (!h->cmp_f (p->hkey, key)) {
239 lsd_mutex_unlock (&h->mutex);
245 hash_insert (hash_t h, const void *key, void *data)
250 if (!h || !key || !data) {
254 lsd_mutex_lock (&h->mutex);
255 assert (h->magic == HASH_MAGIC);
256 slot = h->key_f (key) % h->size;
257 for (p = h->table[slot]; p != NULL; p = p->next) {
258 if (!h->cmp_f (p->hkey, key)) {
264 if (!(p = hash_node_alloc ())) {
265 data = lsd_nomem_error (__FILE__, __LINE__, "hash_insert");
270 p->next = h->table[slot];
275 lsd_mutex_unlock (&h->mutex);
281 hash_remove (hash_t h, const void *key)
283 struct hash_node **pp;
293 lsd_mutex_lock (&h->mutex);
294 assert (h->magic == HASH_MAGIC);
295 slot = h->key_f (key) % h->size;
296 for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &((*pp)->next)) {
297 if (!h->cmp_f (p->hkey, key)) {
305 lsd_mutex_unlock (&h->mutex);
311 hash_delete_if (hash_t h, hash_arg_f arg_f, void *arg)
314 struct hash_node **pp;
322 lsd_mutex_lock (&h->mutex);
323 assert (h->magic == HASH_MAGIC);
324 for (i = 0; i < h->size; i++) {
326 while ((p = *pp) != NULL) {
327 if (arg_f (p->data, p->hkey, arg) > 0) {
340 lsd_mutex_unlock (&h->mutex);
346 hash_for_each (hash_t h, hash_arg_f arg_f, void *arg)
356 lsd_mutex_lock (&h->mutex);
357 assert (h->magic == HASH_MAGIC);
358 for (i = 0; i < h->size; i++) {
359 for (p = h->table[i]; p != NULL; p = p->next) {
360 if (arg_f (p->data, p->hkey, arg) > 0) {
365 lsd_mutex_unlock (&h->mutex);
370 /*****************************************************************************
372 *****************************************************************************/
375 hash_key_string (const char *str)
378 unsigned int hval = 0;
379 const unsigned int multiplier = 31;
381 for (p = (unsigned char *) str; *p != '\0'; p++) {
382 hval += (multiplier * hval) + *p;
388 /*****************************************************************************
390 *****************************************************************************/
392 static struct hash_node *
393 hash_node_alloc (void)
395 /* Allocates a hash node from the freelist.
396 * Memory is allocated in chunks of HASH_ALLOC.
397 * Returns a ptr to the object, or NULL if memory allocation fails.
402 struct hash_node *p = NULL;
404 assert (HASH_ALLOC > 0);
405 lsd_mutex_lock (&hash_free_lock);
407 if (!hash_free_list) {
408 if ((hash_free_list = malloc (HASH_ALLOC * sizeof (*p)))) {
409 for (i = 0; i < HASH_ALLOC - 1; i++)
410 hash_free_list[i].next = &hash_free_list[i+1];
411 hash_free_list[i].next = NULL;
414 if (hash_free_list) {
416 hash_free_list = p->next;
422 if (!(p = malloc (sizeof(*p))))
425 lsd_mutex_unlock (&hash_free_lock);
431 hash_node_free (struct hash_node *node)
433 /* De-allocates the object [node], returning it to the freelist.
435 assert (node != NULL);
436 memset (node, 0, sizeof (*node));
437 lsd_mutex_lock (&hash_free_lock);
439 node->next = hash_free_list;
440 hash_free_list = node;
444 lsd_mutex_unlock (&hash_free_lock);