hash.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:9k
- /*
- * $Id: hash.c,v 1.7 1999/01/24 04:07:01 wessels Exp $
- *
- * DEBUG: section 0 Hash Tables
- * AUTHOR: Harvest Derived
- *
- * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from the
- * Internet community. Development is led by Duane Wessels of the
- * National Laboratory for Applied Network Research and funded by the
- * National Science Foundation. Squid is Copyrighted (C) 1998 by
- * Duane Wessels and the University of California San Diego. Please
- * see the COPYRIGHT file for full details. Squid incorporates
- * software developed and/or copyrighted by other sources. Please see
- * the CREDITS file for full details.
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- */
- #include "config.h"
- #if HAVE_STDIO_H
- #include <stdio.h>
- #endif
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_STRING_H
- #include <string.h>
- #endif
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #if HAVE_GNUMALLLOC_H
- #include <gnumalloc.h>
- #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
- #include <malloc.h>
- #endif
- #if HAVE_ASSERT_H
- #include <assert.h>
- #endif
- #if HAVE_MATH_H
- #include <math.h>
- #endif
- #include "hash.h"
- #include "util.h"
- static void hash_next_bucket(hash_table * hid);
- unsigned int
- hash_string(const void *data, unsigned int size)
- {
- const char *s = data;
- unsigned int n = 0;
- unsigned int j = 0;
- unsigned int i = 0;
- while (*s) {
- j++;
- n ^= 271 * (unsigned) *s++;
- }
- i = n ^ (j * 271);
- return i % size;
- }
- /* the following function(s) were adapted from
- * usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
- /* Hash function from Chris Torek. */
- unsigned int
- hash4(const void *data, unsigned int size)
- {
- const char *key = data;
- size_t loop;
- unsigned int h;
- size_t len;
- #define HASH4a h = (h << 5) - h + *key++;
- #define HASH4b h = (h << 5) + h + *key++;
- #define HASH4 HASH4b
- h = 0;
- len = strlen(key);
- loop = len >> 3;
- switch (len & (8 - 1)) {
- case 0:
- break;
- case 7:
- HASH4;
- /* FALLTHROUGH */
- case 6:
- HASH4;
- /* FALLTHROUGH */
- case 5:
- HASH4;
- /* FALLTHROUGH */
- case 4:
- HASH4;
- /* FALLTHROUGH */
- case 3:
- HASH4;
- /* FALLTHROUGH */
- case 2:
- HASH4;
- /* FALLTHROUGH */
- case 1:
- HASH4;
- }
- while (loop--) {
- HASH4;
- HASH4;
- HASH4;
- HASH4;
- HASH4;
- HASH4;
- HASH4;
- HASH4;
- }
- return h % size;
- }
- /*
- * hash_create - creates a new hash table, uses the cmp_func
- * to compare keys. Returns the identification for the hash table;
- * otherwise returns a negative number on error.
- */
- hash_table *
- hash_create(HASHCMP * cmp_func, int hash_sz, HASHHASH * hash_func)
- {
- hash_table *hid = xcalloc(1, sizeof(hash_table));
- if (!hash_sz)
- hid->size = (unsigned int) DEFAULT_HASH_SIZE;
- else
- hid->size = (unsigned int) hash_sz;
- /* allocate and null the buckets */
- hid->buckets = xcalloc(hid->size, sizeof(hash_link *));
- hid->cmp = cmp_func;
- hid->hash = hash_func;
- hid->next = NULL;
- hid->current_slot = 0;
- return hid;
- }
- /*
- * hash_join - joins a hash_link under its key lnk->key
- * into the hash table 'hid'.
- *
- * It does not copy any data into the hash table, only links pointers.
- */
- void
- hash_join(hash_table * hid, hash_link * lnk)
- {
- int i;
- i = hid->hash(lnk->key, hid->size);
- lnk->next = hid->buckets[i];
- hid->buckets[i] = lnk;
- hid->count++;
- }
- /*
- * hash_lookup - locates the item under the key 'k' in the hash table
- * 'hid'. Returns a pointer to the hash bucket on success; otherwise
- * returns NULL.
- */
- void *
- hash_lookup(hash_table * hid, const void *k)
- {
- hash_link *walker;
- int b;
- assert(k != NULL);
- b = hid->hash(k, hid->size);
- for (walker = hid->buckets[b]; walker != NULL; walker = walker->next) {
- if ((hid->cmp) (k, walker->key) == 0)
- return (walker);
- assert(walker != walker->next);
- }
- return NULL;
- }
- static void
- hash_next_bucket(hash_table * hid)
- {
- while (hid->next == NULL && ++hid->current_slot < hid->size)
- hid->next = hid->buckets[hid->current_slot];
- }
- /*
- * hash_first - initializes the hash table for the hash_next()
- * function.
- */
- void
- hash_first(hash_table * hid)
- {
- assert(NULL == hid->next);
- hid->current_slot = 0;
- hid->next = hid->buckets[hid->current_slot];
- if (NULL == hid->next)
- hash_next_bucket(hid);
- }
- /*
- * hash_next - returns the next item in the hash table 'hid'.
- * Otherwise, returns NULL on error or end of list.
- *
- * MUST call hash_first() before hash_next().
- */
- void *
- hash_next(hash_table * hid)
- {
- hash_link *this = hid->next;
- if (NULL == this)
- return NULL;
- hid->next = this->next;
- if (NULL == hid->next)
- hash_next_bucket(hid);
- return this;
- }
- /*
- * hash_last - resets hash traversal state to NULL
- *
- */
- void
- hash_last(hash_table * hid)
- {
- assert(hid);
- hid->next = NULL;
- hid->current_slot = 0;
- }
- /*
- * hash_remove_link - deletes the given hash_link node from the
- * hash table 'hid'. Does not free the item, only removes it
- * from the list.
- *
- * On success, it returns 0 and deletes the link; otherwise,
- * returns non-zero on error.
- */
- void
- hash_remove_link(hash_table * hid, hash_link * hl)
- {
- hash_link **P;
- int i;
- assert(hl != NULL);
- i = hid->hash(hl->key, hid->size);
- for (P = &hid->buckets[i]; *P; P = &(*P)->next) {
- if (*P != hl)
- continue;
- *P = hl->next;
- if (hid->next == hl) {
- hid->next = hl->next;
- if (NULL == hid->next)
- hash_next_bucket(hid);
- }
- hid->count--;
- return;
- }
- assert(0);
- }
- /*
- * hash_get_bucket - returns the head item of the bucket
- * in the hash table 'hid'. Otherwise, returns NULL on error.
- */
- hash_link *
- hash_get_bucket(hash_table * hid, unsigned int bucket)
- {
- if (bucket >= hid->size)
- return NULL;
- return (hid->buckets[bucket]);
- }
- void
- hashFreeItems(hash_table * hid, HASHFREE * free_func)
- {
- hash_link *l;
- hash_link **list;
- int i = 0;
- int j;
- list = xcalloc(hid->count, sizeof(hash_link *));
- hash_first(hid);
- while ((l = hash_next(hid)) && i < hid->count) {
- *(list + i) = l;
- i++;
- }
- for (j = 0; j < i; j++)
- free_func(*(list + j));
- xfree(list);
- }
- void
- hashFreeMemory(hash_table * hid)
- {
- assert(hid);
- if (hid->buckets)
- xfree(hid->buckets);
- xfree(hid);
- }
- static int hash_primes[] =
- {
- 103,
- 229,
- 467,
- 977,
- 1979,
- 4019,
- 6037,
- 7951,
- 12149,
- 16231,
- 33493,
- 65357
- };
- int
- hashPrime(int n)
- {
- int I = sizeof(hash_primes) / sizeof(int);
- int i;
- int best_prime = hash_primes[0];
- double min = fabs(log((double) n) - log((double) hash_primes[0]));
- double d;
- for (i = 0; i < I; i++) {
- d = fabs(log((double) n) - log((double) hash_primes[i]));
- if (d > min)
- continue;
- min = d;
- best_prime = hash_primes[i];
- }
- return best_prime;
- }
- #ifdef USE_HASH_DRIVER
- /*
- * hash-driver - Run with a big file as stdin to insert each line into the
- * hash table, then prints the whole hash table, then deletes a random item,
- * and prints the table again...
- */
- int
- main(void)
- {
- hash_table *hid;
- int i;
- LOCAL_ARRAY(char, buf, BUFSIZ);
- LOCAL_ARRAY(char, todelete, BUFSIZ);
- hash_link *walker = NULL;
- todelete[0] = ' ';
- printf("initn");
- printf("creating hash tablen");
- if ((hid = hash_create((HASHCMP *) strcmp, 229, hash4)) < 0) {
- printf("hash_create error.n");
- exit(1);
- }
- printf("done creating hash table: %dn", hid);
- while (fgets(buf, BUFSIZ, stdin)) {
- buf[strlen(buf) - 1] = ' ';
- printf("Inserting '%s' for item %p to hash table: %dn",
- buf, buf, hid);
- hash_insert(hid, xstrdup(buf), (void *) 0x12345678);
- if (random() % 17 == 0)
- strcpy(todelete, buf);
- }
- printf("walking hash table...n");
- for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
- printf("item %5d: key: '%s' item: %pn", i++, walker->key,
- walker->item);
- }
- printf("done walking hash table...n");
- if (todelete[0]) {
- printf("deleting %s from %dn", todelete, hid);
- if (hash_delete(hid, todelete))
- printf("hash_delete errorn");
- }
- printf("walking hash table...n");
- for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
- printf("item %5d: key: '%s' item: %pn", i++, walker->key,
- walker->item);
- }
- printf("done walking hash table...n");
- printf("driver finished.n");
- exit(0);
- }
- #endif