/* ** HASH: Simple hash table implementation. ** Copyright (C) 2002 Michael W. Shaffer ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program (see the file COPYING). If not, write to: ** ** The Free Software Foundation, Inc. ** 59 Temple Place, Suite 330, ** Boston, MA 02111-1307 USA */ #include #include "primes.h" #include "list.h" #include "hash.h" /* Peter J. Wienberger's hash */ static unsigned long hash_pjw (char *value) { unsigned long h = 0; unsigned long g = 0; while (*value) { h = (h << 4) + *(value++); if ((g = h & 0xF0000000)) h ^= g >> 24; h &= ~g; } return h; } void hash_table_init (struct hash_table *h) { int i = 0; if (!h) return; if (h->size < 1) h->size = 100; h->size = find_prime (h->size); h->tbl = (struct list *) malloc (h->size * (sizeof (struct list))); if (!h->tbl) return; memset (h->tbl, 0, (h->size * sizeof (struct list))); for (i = 0 ; i < h->size ; i++) { list_init (&(h->tbl[i])); } return; } void hash_table_free (struct hash_table *h) { int i = 0; struct datum *d = NULL; struct list_item *curr = NULL; if (!h) return; for (i = 0 ; i < h->size ; i++) { for (curr = h->tbl[i].head ; curr ; curr = curr->next) { if (curr->data) { d = (struct datum *) curr->data; if (d->key) free (d->key); if (d->val) free (d->val); } } list_free (&(h->tbl[i])); } if (h->tbl) free (h->tbl); h->size = 0; h->tbl = NULL; return; } struct datum *hash_table_insert (struct hash_table *h, struct datum *d) { int slot = 0; struct datum *new = NULL; struct list_item *item = NULL; if (!(d && h && (h->size > 0) && h->tbl)) return NULL; new = (struct datum *) malloc (sizeof (struct datum)); if (!new) goto ERROR; memset (new, 0, (sizeof (struct datum))); new->ksize = d->ksize; new->key = (void *) malloc (new->ksize + 1); if (!new->key) goto ERROR; memset (new->key, 0, (new->ksize + 1)); memcpy (new->key, d->key, new->ksize); new->vsize = d->vsize; new->val = (void *) malloc (new->vsize + 1); if (!new->val) goto ERROR; memset (new->val, 0, (new->vsize + 1)); memcpy (new->val, d->val, new->vsize); slot = (int) (hash_pjw (d->key) % h->size); item = list_insert (&(h->tbl[slot]), (void *) new, sizeof (struct datum)); goto EXIT; ERROR: if (new && (new->key)) free (new->key); if (new && (new->val)) free (new->val); EXIT: if (new) free (new); return (struct datum *) item->data; } struct datum *hash_table_search (struct hash_table *h, struct datum *k) { int slot = 0; struct list_item *curr = NULL; struct datum *d = NULL; if (!(k && h && (h->size > 0) && h->tbl)) goto EXIT; slot = (int) (hash_pjw (k->key) % h->size); for (curr = h->tbl[slot].head ; curr ; curr = curr->next) { d = (struct datum *) curr->data; if (d->ksize == k->ksize){ if (!memcmp (d->key, k->key, d->ksize)) goto EXIT; } } d = NULL; EXIT: return d; } static struct list_item *hash_table_search2 (struct hash_table *h, struct datum *k) { int slot = 0; struct list_item *curr = NULL; struct datum *d = NULL; if (!(k && h && (h->size > 0) && h->tbl)) goto EXIT; slot = (int) (hash_pjw (k->key) % h->size); for (curr = h->tbl[slot].head ; curr ; curr = curr->next) { d = (struct datum *) curr->data; if (d->ksize == k->ksize){ if (!memcmp (d->key, k->key, d->ksize)) goto EXIT; } } curr = NULL; EXIT: return curr; } void hash_table_delete (struct hash_table *h, struct datum *k) { struct datum *d = NULL; struct list_item *l = NULL; if (!(k && h && (h->size > 0) && h->tbl)) return; if ((l = hash_table_search2 (h, k))) { d = (struct datum *) l->data; if (d->key) free (d->key); if (d->val) free (d->val); list_delete ((struct list_item *) l); } return; }