hash.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:9k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: hash.c,v 1.7 1999/01/24 04:07:01 wessels Exp $
  3.  *
  4.  * DEBUG: section 0     Hash Tables
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "config.h"
  35. #if HAVE_STDIO_H
  36. #include <stdio.h>
  37. #endif
  38. #if HAVE_STDLIB_H
  39. #include <stdlib.h>
  40. #endif
  41. #if HAVE_STRING_H
  42. #include <string.h>
  43. #endif
  44. #if HAVE_UNISTD_H
  45. #include <unistd.h>
  46. #endif
  47. #if HAVE_GNUMALLLOC_H
  48. #include <gnumalloc.h>
  49. #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
  50. #include <malloc.h>
  51. #endif
  52. #if HAVE_ASSERT_H
  53. #include <assert.h>
  54. #endif
  55. #if HAVE_MATH_H
  56. #include <math.h>
  57. #endif
  58. #include "hash.h"
  59. #include "util.h"
  60. static void hash_next_bucket(hash_table * hid);
  61. unsigned int
  62. hash_string(const void *data, unsigned int size)
  63. {
  64.     const char *s = data;
  65.     unsigned int n = 0;
  66.     unsigned int j = 0;
  67.     unsigned int i = 0;
  68.     while (*s) {
  69. j++;
  70. n ^= 271 * (unsigned) *s++;
  71.     }
  72.     i = n ^ (j * 271);
  73.     return i % size;
  74. }
  75. /* the following function(s) were adapted from
  76.  *    usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
  77. /* Hash function from Chris Torek. */
  78. unsigned int
  79. hash4(const void *data, unsigned int size)
  80. {
  81.     const char *key = data;
  82.     size_t loop;
  83.     unsigned int h;
  84.     size_t len;
  85. #define HASH4a   h = (h << 5) - h + *key++;
  86. #define HASH4b   h = (h << 5) + h + *key++;
  87. #define HASH4 HASH4b
  88.     h = 0;
  89.     len = strlen(key);
  90.     loop = len >> 3;
  91.     switch (len & (8 - 1)) {
  92.     case 0:
  93. break;
  94.     case 7:
  95. HASH4;
  96. /* FALLTHROUGH */
  97.     case 6:
  98. HASH4;
  99. /* FALLTHROUGH */
  100.     case 5:
  101. HASH4;
  102. /* FALLTHROUGH */
  103.     case 4:
  104. HASH4;
  105. /* FALLTHROUGH */
  106.     case 3:
  107. HASH4;
  108. /* FALLTHROUGH */
  109.     case 2:
  110. HASH4;
  111. /* FALLTHROUGH */
  112.     case 1:
  113. HASH4;
  114.     }
  115.     while (loop--) {
  116. HASH4;
  117. HASH4;
  118. HASH4;
  119. HASH4;
  120. HASH4;
  121. HASH4;
  122. HASH4;
  123. HASH4;
  124.     }
  125.     return h % size;
  126. }
  127. /*
  128.  *  hash_create - creates a new hash table, uses the cmp_func
  129.  *  to compare keys.  Returns the identification for the hash table;
  130.  *  otherwise returns a negative number on error.
  131.  */
  132. hash_table *
  133. hash_create(HASHCMP * cmp_func, int hash_sz, HASHHASH * hash_func)
  134. {
  135.     hash_table *hid = xcalloc(1, sizeof(hash_table));
  136.     if (!hash_sz)
  137. hid->size = (unsigned int) DEFAULT_HASH_SIZE;
  138.     else
  139. hid->size = (unsigned int) hash_sz;
  140.     /* allocate and null the buckets */
  141.     hid->buckets = xcalloc(hid->size, sizeof(hash_link *));
  142.     hid->cmp = cmp_func;
  143.     hid->hash = hash_func;
  144.     hid->next = NULL;
  145.     hid->current_slot = 0;
  146.     return hid;
  147. }
  148. /*
  149.  *  hash_join - joins a hash_link under its key lnk->key
  150.  *  into the hash table 'hid'.  
  151.  *
  152.  *  It does not copy any data into the hash table, only links pointers.
  153.  */
  154. void
  155. hash_join(hash_table * hid, hash_link * lnk)
  156. {
  157.     int i;
  158.     i = hid->hash(lnk->key, hid->size);
  159.     lnk->next = hid->buckets[i];
  160.     hid->buckets[i] = lnk;
  161.     hid->count++;
  162. }
  163. /*
  164.  *  hash_lookup - locates the item under the key 'k' in the hash table
  165.  *  'hid'.  Returns a pointer to the hash bucket on success; otherwise
  166.  *  returns NULL.
  167.  */
  168. void *
  169. hash_lookup(hash_table * hid, const void *k)
  170. {
  171.     hash_link *walker;
  172.     int b;
  173.     assert(k != NULL);
  174.     b = hid->hash(k, hid->size);
  175.     for (walker = hid->buckets[b]; walker != NULL; walker = walker->next) {
  176. if ((hid->cmp) (k, walker->key) == 0)
  177.     return (walker);
  178. assert(walker != walker->next);
  179.     }
  180.     return NULL;
  181. }
  182. static void
  183. hash_next_bucket(hash_table * hid)
  184. {
  185.     while (hid->next == NULL && ++hid->current_slot < hid->size)
  186. hid->next = hid->buckets[hid->current_slot];
  187. }
  188. /*
  189.  *  hash_first - initializes the hash table for the hash_next()
  190.  *  function.
  191.  */
  192. void
  193. hash_first(hash_table * hid)
  194. {
  195.     assert(NULL == hid->next);
  196.     hid->current_slot = 0;
  197.     hid->next = hid->buckets[hid->current_slot];
  198.     if (NULL == hid->next)
  199. hash_next_bucket(hid);
  200. }
  201. /*
  202.  *  hash_next - returns the next item in the hash table 'hid'.
  203.  *  Otherwise, returns NULL on error or end of list.  
  204.  *
  205.  *  MUST call hash_first() before hash_next().
  206.  */
  207. void *
  208. hash_next(hash_table * hid)
  209. {
  210.     hash_link *this = hid->next;
  211.     if (NULL == this)
  212. return NULL;
  213.     hid->next = this->next;
  214.     if (NULL == hid->next)
  215. hash_next_bucket(hid);
  216.     return this;
  217. }
  218. /*
  219.  *  hash_last - resets hash traversal state to NULL
  220.  *
  221.  */
  222. void
  223. hash_last(hash_table * hid)
  224. {
  225.     assert(hid);
  226.     hid->next = NULL;
  227.     hid->current_slot = 0;
  228. }
  229. /*
  230.  *  hash_remove_link - deletes the given hash_link node from the 
  231.  *  hash table 'hid'.  Does not free the item, only removes it
  232.  *  from the list.
  233.  *
  234.  *  On success, it returns 0 and deletes the link; otherwise, 
  235.  *  returns non-zero on error.
  236.  */
  237. void
  238. hash_remove_link(hash_table * hid, hash_link * hl)
  239. {
  240.     hash_link **P;
  241.     int i;
  242.     assert(hl != NULL);
  243.     i = hid->hash(hl->key, hid->size);
  244.     for (P = &hid->buckets[i]; *P; P = &(*P)->next) {
  245. if (*P != hl)
  246.     continue;
  247. *P = hl->next;
  248. if (hid->next == hl) {
  249.     hid->next = hl->next;
  250.     if (NULL == hid->next)
  251. hash_next_bucket(hid);
  252. }
  253. hid->count--;
  254. return;
  255.     }
  256.     assert(0);
  257. }
  258. /*
  259.  *  hash_get_bucket - returns the head item of the bucket 
  260.  *  in the hash table 'hid'. Otherwise, returns NULL on error.
  261.  */
  262. hash_link *
  263. hash_get_bucket(hash_table * hid, unsigned int bucket)
  264. {
  265.     if (bucket >= hid->size)
  266. return NULL;
  267.     return (hid->buckets[bucket]);
  268. }
  269. void
  270. hashFreeItems(hash_table * hid, HASHFREE * free_func)
  271. {
  272.     hash_link *l;
  273.     hash_link **list;
  274.     int i = 0;
  275.     int j;
  276.     list = xcalloc(hid->count, sizeof(hash_link *));
  277.     hash_first(hid);
  278.     while ((l = hash_next(hid)) && i < hid->count) {
  279. *(list + i) = l;
  280. i++;
  281.     }
  282.     for (j = 0; j < i; j++)
  283. free_func(*(list + j));
  284.     xfree(list);
  285. }
  286. void
  287. hashFreeMemory(hash_table * hid)
  288. {
  289.     assert(hid);
  290.     if (hid->buckets)
  291.         xfree(hid->buckets);
  292.     xfree(hid);
  293. }
  294. static int hash_primes[] =
  295. {
  296.     103,
  297.     229,
  298.     467,
  299.     977,
  300.     1979,
  301.     4019,
  302.     6037,
  303.     7951,
  304.     12149,
  305.     16231,
  306.     33493,
  307.     65357
  308. };
  309. int
  310. hashPrime(int n)
  311. {
  312.     int I = sizeof(hash_primes) / sizeof(int);
  313.     int i;
  314.     int best_prime = hash_primes[0];
  315.     double min = fabs(log((double) n) - log((double) hash_primes[0]));
  316.     double d;
  317.     for (i = 0; i < I; i++) {
  318. d = fabs(log((double) n) - log((double) hash_primes[i]));
  319. if (d > min)
  320.     continue;
  321. min = d;
  322. best_prime = hash_primes[i];
  323.     }
  324.     return best_prime;
  325. }
  326. #ifdef USE_HASH_DRIVER
  327. /*
  328.  *  hash-driver - Run with a big file as stdin to insert each line into the
  329.  *  hash table, then prints the whole hash table, then deletes a random item,
  330.  *  and prints the table again...
  331.  */
  332. int
  333. main(void)
  334. {
  335.     hash_table *hid;
  336.     int i;
  337.     LOCAL_ARRAY(char, buf, BUFSIZ);
  338.     LOCAL_ARRAY(char, todelete, BUFSIZ);
  339.     hash_link *walker = NULL;
  340.     todelete[0] = '';
  341.     printf("initn");
  342.     printf("creating hash tablen");
  343.     if ((hid = hash_create((HASHCMP *) strcmp, 229, hash4)) < 0) {
  344. printf("hash_create error.n");
  345. exit(1);
  346.     }
  347.     printf("done creating hash table: %dn", hid);
  348.     while (fgets(buf, BUFSIZ, stdin)) {
  349. buf[strlen(buf) - 1] = '';
  350. printf("Inserting '%s' for item %p to hash table: %dn",
  351.     buf, buf, hid);
  352. hash_insert(hid, xstrdup(buf), (void *) 0x12345678);
  353. if (random() % 17 == 0)
  354.     strcpy(todelete, buf);
  355.     }
  356.     printf("walking hash table...n");
  357.     for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
  358. printf("item %5d: key: '%s' item: %pn", i++, walker->key,
  359.     walker->item);
  360.     }
  361.     printf("done walking hash table...n");
  362.     if (todelete[0]) {
  363. printf("deleting %s from %dn", todelete, hid);
  364. if (hash_delete(hid, todelete))
  365.     printf("hash_delete errorn");
  366.     }
  367.     printf("walking hash table...n");
  368.     for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
  369. printf("item %5d: key: '%s' item: %pn", i++, walker->key,
  370.     walker->item);
  371.     }
  372.     printf("done walking hash table...n");
  373.     printf("driver finished.n");
  374.     exit(0);
  375. }
  376. #endif