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

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: hash.c,v 1.5 1998/07/22 20:38:08 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
  13.  *  the National Science Foundation.
  14.  *
  15.  *  This program is free software; you can redistribute it and/or modify
  16.  *  it under the terms of the GNU General Public License as published by
  17.  *  the Free Software Foundation; either version 2 of the License, or
  18.  *  (at your option) any later version.
  19.  *  
  20.  *  This program is distributed in the hope that it will be useful,
  21.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  *  GNU General Public License for more details.
  24.  *  
  25.  *  You should have received a copy of the GNU General Public License
  26.  *  along with this program; if not, write to the Free Software
  27.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  28.  *  
  29.  */
  30. #include <unistd.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <ctype.h>
  35. #include <sys/time.h>
  36. #include <strings.h>
  37. #include <assert.h>
  38. #include "hash.h"
  39. #undef free
  40. extern void my_free(char *, int , void *);
  41. #define free(a) my_free(__FILE__, __LINE__, a)
  42. extern void print_stats();
  43. /*
  44.  *  hash_url() - Returns a well-distributed hash function for URLs.
  45.  *  The best way is to sum up the last half of the string.
  46.  *  Adapted from code written by Mic Bowman.  -Darren
  47.  *  Generates a standard deviation = 15.73
  48.  */
  49. unsigned int
  50. hash_url(const void *data, unsigned int size)
  51. {
  52.     const char *s = data;
  53.     unsigned int i, j, n;
  54.     j = strlen(s);
  55.     for (i = j / 2, n = 0; i < j; i++)
  56. n ^= 271 * (unsigned) s[i];
  57.     i = n ^ (j * 271);
  58.     return i % size;
  59. }
  60. unsigned int
  61. hash_string(const void *data, unsigned int size)
  62. {
  63.     const char *s = data;
  64.     unsigned int n = 0;
  65.     unsigned int j = 0;
  66.     unsigned int i = 0;
  67.     while (*s) {
  68. j++;
  69. n ^= 271 * (unsigned) *s++;
  70.     }
  71.     i = n ^ (j * 271);
  72.     return i % size;
  73. }
  74. /* the following 4 functions were adapted from
  75.  *    usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
  76. /*
  77.  * HASH FUNCTIONS
  78.  *
  79.  * Assume that we've already split the bucket to which this key hashes,
  80.  * calculate that bucket, and check that in fact we did already split it.
  81.  *
  82.  * This came from ejb's hsearch.
  83.  */
  84. #define PRIME1 37
  85. #define PRIME2 1048583
  86. /* Hash function from Chris Torek. */
  87. unsigned int
  88. hash4(const void *data, unsigned int size)
  89. {
  90.     const char *key = data;
  91.     size_t loop;
  92.     unsigned int h;
  93.     size_t len;
  94. #define HASH4a   h = (h << 5) - h + *key++;
  95. #define HASH4b   h = (h << 5) + h + *key++;
  96. #define HASH4 HASH4b
  97.     h = 0;
  98.     len = strlen(key);
  99.     loop = (len + 8 - 1) >> 3;
  100.     switch (len & (8 - 1)) {
  101.     case 0:
  102. do {
  103.     HASH4;
  104.     /* FALLTHROUGH */
  105.     case 7:
  106.     HASH4;
  107.     /* FALLTHROUGH */
  108.     case 6:
  109.     HASH4;
  110.     /* FALLTHROUGH */
  111.     case 5:
  112.     HASH4;
  113.     /* FALLTHROUGH */
  114.     case 4:
  115.     HASH4;
  116.     /* FALLTHROUGH */
  117.     case 3:
  118.     HASH4;
  119.     /* FALLTHROUGH */
  120.     case 2:
  121.     HASH4;
  122.     /* FALLTHROUGH */
  123.     case 1:
  124.     HASH4;
  125. } while (--loop);
  126.     }
  127.     return h % size;
  128. }
  129. /*
  130.  *  hash_create - creates a new hash table, uses the cmp_func
  131.  *  to compare keys.  Returns the identification for the hash table;
  132.  *  otherwise returns a negative number on error.
  133.  */
  134. hash_table *
  135. hash_create(HASHCMP * cmp_func, int hash_sz, HASHHASH * hash_func)
  136. {
  137.     hash_table *hid = calloc(1, sizeof(hash_table));
  138.     if (!hash_sz)
  139. hid->size = (unsigned int) DEFAULT_HASH_SIZE;
  140.     else
  141. hid->size = (unsigned int) hash_sz;
  142.     /* allocate and null the buckets */
  143.     hid->buckets = calloc(hid->size, sizeof(hash_link *));
  144.     hid->cmp = cmp_func;
  145.     hid->hash = hash_func;
  146.     hid->current_ptr = NULL;
  147.     hid->current_slot = 0;
  148.     return hid;
  149. }
  150. /*
  151.  *  hash_insert - inserts the given item 'item' under the given key 'k'
  152.  *  into the hash table 'hid'.  Returns non-zero on error; otherwise,
  153.  *  returns 0 and inserts the item.
  154.  *
  155.  *  It does not copy any data into the hash table, only pointers.
  156.  */
  157. void
  158. hash_insert(hash_table * hid, const char *k, void *item)
  159. {
  160.     int i;
  161.     hash_link *new;
  162.     assert(k != NULL);
  163.     /* Add to the given hash table 'hid' */
  164.     new = calloc(1, sizeof(hash_link));
  165.     if (!new) {
  166. fprintf(stderr,"calloc failed!n");
  167. print_stats();
  168. exit(1);
  169.     }
  170.     new->item = item;
  171.     new->key = (char *) k;
  172.     i = hid->hash(k, hid->size);
  173.     new->next = hid->buckets[i];
  174.     hid->buckets[i] = new;
  175. }
  176. /*
  177.  *  hash_join - joins a hash_link under its key lnk->key
  178.  *  into the hash table 'hid'.  
  179.  *
  180.  *  It does not copy any data into the hash table, only links pointers.
  181.  */
  182. void
  183. hash_join(hash_table * hid, hash_link * lnk)
  184. {
  185.     int i;
  186.     i = hid->hash(lnk->key, hid->size);
  187.     lnk->next = hid->buckets[i];
  188.     hid->buckets[i] = lnk;
  189. }
  190. /*
  191.  *  hash_lookup - locates the item under the key 'k' in the hash table
  192.  *  'hid'.  Returns a pointer to the hash bucket on success; otherwise
  193.  *  returns NULL.
  194.  */
  195. hash_link *
  196. hash_lookup(hash_table * hid, const void *k)
  197. {
  198.     hash_link *walker;
  199.     int b;
  200.     assert(k != NULL);
  201.     b = hid->hash(k, hid->size);
  202.     for (walker = hid->buckets[b]; walker != NULL; walker = walker->next) {
  203. if ((hid->cmp) (k, walker->key) == 0)
  204.     return (walker);
  205. assert(walker != walker->next);
  206.     }
  207.     return NULL;
  208. }
  209. /*
  210.  *  hash_first - returns the first item in the hash table 'hid'.
  211.  *  Otherwise, returns NULL on error.
  212.  */
  213. hash_link *
  214. hash_first(hash_table * hid)
  215. {
  216.     int i;
  217.     for (i = 0; i < hid->size; i++) {
  218. hid->current_slot = i;
  219. if (hid->buckets[i] != NULL)
  220.     return (hid->current_ptr = hid->buckets[i]);
  221.     }
  222.     return NULL;
  223. }
  224. /*
  225.  *  hash_next - returns the next item in the hash table 'hid'.
  226.  *  Otherwise, returns NULL on error or end of list.  
  227.  *
  228.  *  MUST call hash_first() before hash_next().
  229.  */
  230. hash_link *
  231. hash_next(hash_table * hid)
  232. {
  233.     int i;
  234.     if (hid->current_ptr != NULL) {
  235. hid->current_ptr = hid->current_ptr->next;
  236. if (hid->current_ptr != NULL)
  237.     return (hid->current_ptr); /* next item */
  238.     }
  239.     /* find next bucket */
  240.     for (i = hid->current_slot + 1; i < hid->size; i++) {
  241. hid->current_slot = i;
  242. if (hid->buckets[i] != NULL)
  243.     return (hid->current_ptr = hid->buckets[i]);
  244.     }
  245.     return NULL; /* end of list */
  246. }
  247. int
  248. hash_delete(hash_table * hid, const char *key)
  249. {
  250.     return hash_delete_link(hid, hash_lookup(hid, key));
  251. }
  252. /*
  253.  *  hash_delete_link - deletes the given hash_link node from the 
  254.  *  hash table 'hid'. If FreeLink then free the given hash_link.
  255.  *
  256.  *  On success, it returns 0 and deletes the link; otherwise, 
  257.  *  returns non-zero on error.
  258.  */
  259. int
  260. hash_unlink(hash_table * hid, hash_link * hl, int FreeLink)
  261. {
  262.     hash_link *walker, *prev;
  263.     int i;
  264.     if (hl == NULL)
  265. return -1;
  266.     i = hid->hash(hl->key, hid->size);
  267.     for (prev = NULL, walker = hid->buckets[i];
  268. walker != NULL; prev = walker, walker = walker->next) {
  269. if (walker == hl) {
  270.     if (prev == NULL) { /* it's the head */
  271. hid->buckets[i] = walker->next;
  272.     } else {
  273. prev->next = walker->next; /* skip it */
  274.     }
  275.     /* fix walker state if needed */
  276.     if (walker == hid->current_ptr)
  277. hid->current_ptr = walker->next;
  278.     if (FreeLink) {
  279. if (walker) {
  280. free(walker);
  281. }
  282.     }
  283.     return 0;
  284. }
  285.     }
  286.     return 1;
  287. }
  288. /* take link off and free link node */
  289. int
  290. hash_delete_link(hash_table * hid, hash_link * hl)
  291. {
  292.     return (hash_unlink(hid, hl, 1));
  293. }
  294. /* take link off only */
  295. int
  296. hash_remove_link(hash_table * hid, hash_link * hl)
  297. {
  298.     return (hash_unlink(hid, hl, 0));
  299. }
  300. /*
  301.  *  hash_get_bucket - returns the head item of the bucket 
  302.  *  in the hash table 'hid'. Otherwise, returns NULL on error.
  303.  */
  304. hash_link *
  305. hash_get_bucket(hash_table * hid, unsigned int bucket)
  306. {
  307.     if (bucket >= hid->size)
  308. return NULL;
  309.     return (hid->buckets[bucket]);
  310. }
  311. void
  312. hashFreeMemory(hash_table * hid)
  313. {
  314. if (hid->buckets);
  315.     free(hid->buckets);
  316. if (hid)
  317.     free(hid);
  318. }
  319. #ifdef USE_HASH_DRIVER
  320. /*
  321.  *  hash-driver - Run with a big file as stdin to insert each line into the
  322.  *  hash table, then prints the whole hash table, then deletes a random item,
  323.  *  and prints the table again...
  324.  */
  325. int
  326. main(void)
  327. {
  328.     hash_table *hid;
  329.     int i;
  330.     LOCAL_ARRAY(char, buf, BUFSIZ);
  331.     LOCAL_ARRAY(char, todelete, BUFSIZ);
  332.     hash_link *walker = NULL;
  333.     todelete[0] = '';
  334.     printf("initn");
  335.     printf("creating hash tablen");
  336.     if ((hid = hash_create(strcmp, 229, hash_string)) < 0) {
  337. printf("hash_create error.n");
  338. exit(1);
  339.     }
  340.     printf("done creating hash table: %dn", hid);
  341.     while (fgets(buf, BUFSIZ, stdin)) {
  342. buf[strlen(buf) - 1] = '';
  343. printf("Inserting '%s' for item %p to hash table: %dn",
  344.     buf, buf, hid);
  345. hash_insert(hid, xstrdup(buf), (void *) 0x12345678);
  346. if (random() % 17 == 0)
  347.     strcpy(todelete, buf);
  348.     }
  349.     printf("walking hash table...n");
  350.     for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
  351. printf("item %5d: key: '%s' item: %pn", i++, walker->key,
  352.     walker->item);
  353.     }
  354.     printf("done walking hash table...n");
  355.     if (todelete[0]) {
  356. printf("deleting %s from %dn", todelete, hid);
  357. if (hash_delete(hid, todelete))
  358.     printf("hash_delete errorn");
  359.     }
  360.     printf("walking hash table...n");
  361.     for (i = 0, walker = hash_first(hid); walker; walker = hash_next(hid)) {
  362. printf("item %5d: key: '%s' item: %pn", i++, walker->key,
  363.     walker->item);
  364.     }
  365.     printf("done walking hash table...n");
  366.     printf("driver finished.n");
  367.     exit(0);
  368. }
  369. #endif