home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / mcqueer-lib / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-09  |  11.3 KB  |  494 lines

  1. #include <stdio.h>
  2.  
  3. /*
  4. **
  5. **    Copyright (c) 1987, Robert L. McQueer
  6. **        All Rights Reserved
  7. **
  8. ** Permission granted for use, modification and redistribution of this
  9. ** software provided that no use is made for commercial gain without the
  10. ** written consent of the author, that all copyright notices remain intact,
  11. ** and that all changes are clearly documented.  No warranty of any kind
  12. ** concerning any use which may be made of this software is offered or implied.
  13. **
  14. */
  15.  
  16. /*
  17. ** generic hash table routines.
  18. **
  19. **    htab_init - initialize a new hash table
  20. **    htab_free - destroy a hash table, freeing associated memory
  21. **    htab_clear - remove all hash table entries
  22. **    htab_find - find entry
  23. **    htab_del - delete entry
  24. **    htab_enter - enter item into table
  25. **    htab_list - scan hash table entries.
  26. **
  27. ** Multiple hash tables may be used.  Caller may provide key comparison
  28. ** and hash routines, or use defaults.
  29. */
  30.  
  31. /*
  32. ** HASHMAGIC define may be used to compile a version of these routines
  33. ** which will catch bad context blocks passed in by client routines
  34. ** through a magic number check.  If defined, HASHMAGIC should be the
  35. ** actual number to use for a magic number.  Configurable so that you
  36. ** may avoid the overhead of checking it all the time in these routines
  37. ** which may have high entry rates.
  38. */
  39.  
  40. /*
  41. ** allocation: nodes are allocated starting with a block of ALLOCINIT,
  42. ** doubling the size for the next allocation as long as the size is strictly
  43. ** less than ALLOCLIMIT.  If you make ALLOCLIMIT a value encountered by
  44. ** successive doubling of ALLOCINIT, that will be the final size, otherwise the
  45. ** next doubling larger.
  46. **
  47. ** The idea of this stunt is that we don't know whether the caller is going
  48. ** to make a lot of entries, or just a few.  So we start out allocating
  49. ** just a few nodes at a crack, and as the caller makes more and more
  50. ** entries, allocate bigger bunches.  For memory-restrictive environments
  51. ** like MS-DOS, one could set ALLOCLIMIT low & simply pay the penalty for
  52. ** lots of malloc calls.
  53. */
  54. #define ALLOCINIT 25
  55. #define ALLOCLIMIT 800
  56.  
  57. #define MAGCHECK(T,N) if (T->magic != HASHMAGIC) fatal(Merr,N)
  58.  
  59. typedef struct _htab
  60. {
  61.     struct _htab *next;
  62.     char *key;
  63.     char *data;
  64. } HASHTAB;
  65.  
  66. typedef struct _faddr
  67. {
  68.     struct _faddr *next;
  69. } FADDR;
  70.  
  71. /*
  72. ** fpool, tpool - tpool is the pool of available nodes.  Every time
  73. ** a new block is allocated, one FADDR is allocated along with it.
  74. ** The address allocated is coerced into the FADDR and placed on fpool
  75. ** to facilitate freeing.
  76. */
  77.  
  78. typedef struct
  79. {
  80. #ifdef HASHMAGIC
  81.     int magic;
  82. #endif
  83.     HASHTAB **tab;        /* hash table */
  84.     HASHTAB *tpool;        /* available nodes */
  85.     HASHTAB *srch;        /* current search pointer for htab_list */
  86.     FADDR *fpool;        /* alloc pointers for htab_free */
  87.     int (*afail)();        /* allocation error handler */
  88.     int (*compare)();    /* comparison routine */
  89.     int (*hashfunc)();    /* hash function */
  90.     int size;        /* size of table (length of tab item) */
  91.     int ablock;        /* current allocation block size */
  92.     int srchidx;        /* current table index for htab_list */
  93. } CONTEXT;
  94.  
  95. extern char *malloc();
  96.  
  97. #ifdef HASHMAGIC
  98. static char *Merr = "Bad magic number in hash table context block, %s()";
  99. #endif
  100.  
  101. /*
  102. ** free hash table.  tab is pointer returned by htab_init.
  103. */
  104. htab_free(tab)
  105. char *tab;
  106. {
  107.     register FADDR *ptr, *next;
  108.     int i;
  109.     register CONTEXT *cb;
  110.  
  111.     cb = (CONTEXT *) tab;
  112.  
  113. #ifdef HASHMAGIC
  114.     MAGCHECK(cb,"htab_free");
  115.     ++(cb->magic);
  116. #endif
  117.  
  118.     for (ptr = cb->fpool; ptr != NULL; ptr = next)
  119.     {
  120.         next = ptr->next;
  121.         free ((char *) ptr);
  122.     }
  123.  
  124.     free (tab);
  125. }
  126.  
  127. /*
  128. ** remove all hash table entries.  Does not free memory, simply restores
  129. ** empty table, as if one had called htab_delete on all the keys.  tab is
  130. ** pointer returned by htab_init.
  131. */
  132. htab_clear(tab)
  133. char *tab;
  134. {
  135.     register CONTEXT *cb;
  136.     register HASHTAB **tptr;
  137.     register HASHTAB *nptr;
  138.     int i;
  139.  
  140.     cb = (CONTEXT *) tab;
  141.  
  142. #ifdef HASHMAGIC
  143.     MAGCHECK(cb,"htab_clear");
  144. #endif
  145.  
  146.     tptr = cb->tab;
  147.  
  148.     for (i=0; i < cb->size; ++i,++tptr)
  149.     {
  150.         nptr = *tptr;
  151.         if (nptr == NULL)
  152.             continue;
  153.         while (nptr->next != NULL)
  154.             nptr = nptr->next;
  155.         nptr->next = cb->tpool;
  156.         cb->tpool = *tptr;
  157.         *tptr = NULL;
  158.     }
  159.  
  160.     /* force any open htab_list's to return empty */
  161.     cb->srch = NULL;
  162.     cb->srchidx = cb->size;
  163. }
  164.  
  165. /*
  166. ** initialize a hash table.  Returns a pointer to be used with other
  167. ** calls, NULL for failure.
  168. **
  169. ** The hash table will be maintained as a linked list for each node,
  170. ** so any number of entries can be made to it, whatever the value for
  171. ** size (>100% density is perfectly OK).
  172. **
  173. **    size - size of table.  If hfunc is NULL, will be incremented
  174. **        up to a prime size to suit the type of hash function
  175. **        used by default.  Caller may find out the actual size
  176. **        by calling next_prime().
  177. **
  178. **    allocfail - routine to call in case of memory allocation failure.
  179. **        If NULL, allocation failure will make a call to fatal().
  180. **
  181. **    comp - routine used to compare keys.  returns 0 if equal, non-zero
  182. **        otherwise.  If NULL, strcmp() will be used.  Your own will
  183. **        have to be provided if your keys are something other than
  184. **        strings.  These routines will always call this with the
  185. **        comparison key as the first argument, and the one in the
  186. **        table already as a second argument.  This fact is most
  187. **        useful for making comparisons up to the length of the entered
  188. **        key, for instance.
  189. **
  190. **    hfunc - hash function.  called as (*hfunc)(key, size).  size argument
  191. **        may be ignored if function was written for a specific size.
  192. **        Must return an integer between 0 and size-1.  If NULL, the
  193. **        default hash function is the typical "string-divided-modulo
  194. **        -table-size" algorithm.
  195. */
  196. char *
  197. htab_init(size,allocfail,comp,hfunc)
  198. int size;
  199. int (*allocfail)();
  200. int (*comp)();
  201. int (*hfunc)();
  202. {
  203.     int def_afail();
  204.     int strcmp();
  205.     int hash();
  206.     int i;
  207.     CONTEXT *cb;
  208.  
  209.     if (allocfail == NULL)
  210.         allocfail = def_afail;
  211.  
  212.     if (comp == NULL)
  213.         comp = strcmp;
  214.  
  215.     if (hfunc == NULL)
  216.     {
  217.         size = next_prime(size);
  218.         hfunc = hash;
  219.     }
  220.  
  221.     i = sizeof(CONTEXT) + size * sizeof(HASHTAB *);
  222.  
  223.     if ((cb = (CONTEXT *) malloc(i)) == NULL)
  224.     {
  225.         (*allocfail)();
  226.         return (NULL);
  227.     }
  228.  
  229. #ifdef HASHMAGIC
  230.     cb->magic = HASHMAGIC;
  231. #endif
  232.  
  233.     cb->afail = allocfail;
  234.     cb->compare = comp;
  235.     cb->hashfunc = hfunc;
  236.     cb->size = size;
  237.     cb->tab = (HASHTAB **)(cb+1);
  238.  
  239.     for (i=0; i < cb->size; ++i)
  240.         (cb->tab)[i] = NULL;
  241.     cb->tpool = NULL;
  242.     cb->fpool = NULL;
  243.     cb->ablock = ALLOCINIT;
  244.  
  245.     /* safety, in case somebody calls htab_list wrong */
  246.     cb->srch = NULL;
  247.     cb->srchidx = size;
  248.  
  249.     return ((char *) cb);
  250. }
  251.  
  252.  
  253. /*
  254. ** find an entry in hash table.  The pointer returned is NULL for
  255. ** failure, or the data pointer associated with the key in htab_enter.
  256. **
  257. **    tab - table pointer returned by htab_init.
  258. **    s - search key.
  259. */
  260. char *
  261. htab_find(tab,s)
  262. char *tab;
  263. char *s;
  264. {
  265.     register HASHTAB *ptr;
  266.     register CONTEXT *cb;
  267.  
  268.     cb = (CONTEXT *) tab;
  269.  
  270. #ifdef HASHMAGIC
  271.     MAGCHECK(cb,"htab_find");
  272. #endif
  273.  
  274.     for (ptr = (cb->tab)[(*(cb->hashfunc))(s,cb->size)];
  275.                     ptr != NULL; ptr = ptr->next)
  276.     {
  277.         if ((*(cb->compare))(s,ptr->key) == 0)
  278.             return (ptr->data);
  279.     }
  280.  
  281.     return (NULL);
  282. }
  283.  
  284. /*
  285. ** delete a hash table entry.  Returns 0 for success, <0 for no entry.
  286. **
  287. **    tab - table pointer returned by htab_init.
  288. **    s - search key.
  289. */
  290. htab_del(tab,s)
  291. char *tab;
  292. char *s;
  293. {
  294.     register HASHTAB *ptr;
  295.     register CONTEXT *cb;
  296.     register HASHTAB *pred;
  297.     int idx;
  298.  
  299.     cb = (CONTEXT *) tab;
  300.  
  301. #ifdef HASHMAGIC
  302.     MAGCHECK(cb,"htab_del");
  303. #endif
  304.  
  305.     pred = NULL;
  306.     for (ptr = (cb->tab)[idx = (*(cb->hashfunc))(s,cb->size)];
  307.                         ptr != NULL; ptr = ptr->next)
  308.     {
  309.         if ((*(cb->compare))(s,ptr->key) == 0)
  310.             break;
  311.         pred = ptr;
  312.     }
  313.  
  314.     if (ptr == NULL)
  315.         return (-1);
  316.  
  317.     /*
  318.     ** if we're deleting the current search index in the middle
  319.     ** of an htab_list, go to next item.
  320.     */
  321.     if (ptr == cb->srch)
  322.         cb->srch = ptr->next;
  323.  
  324.     if (pred == NULL)
  325.         (cb->tab)[idx] = ptr->next;
  326.     else
  327.         pred->next = ptr->next;
  328.     ptr->next = cb->tpool;
  329.     cb->tpool = ptr;
  330.  
  331.     return (0);
  332. }
  333.  
  334. /*
  335. ** enter new item into hash table:
  336. **
  337. **    tab - table pointer from htab_init.
  338. **    s - key.
  339. **    data - data to associate with key.  In most cases, will probably
  340. **        actually be a pointer to some sort of structure known
  341. **        to the caller.
  342. **
  343. **    both s and data should point to storage valid for the entire life of
  344. **    the table.  htab_enter can not allocate copies of either of these
  345. **    things since it does not know their structure (if you provided 
  346. **    comparison & hash routines, the key may not actually be a string).
  347. **    htab_enter WILL allocate actual table nodes.  Returns 0 for success,
  348. **    -1 for failure.  Failure return is possible only if allocation
  349. **    failure occurs, and was not set up as fatal in htab_init().
  350. */
  351. htab_enter(tab,s,data)
  352. char *tab;
  353. char *s;
  354. char *data;
  355. {
  356.     register HASHTAB *ptr;
  357.     register CONTEXT *cb;
  358.     HASHTAB *get_node();
  359.     int i;
  360.  
  361.     cb = (CONTEXT *) tab;
  362.  
  363. #ifdef HASHMAGIC
  364.     MAGCHECK(cb,"htab_enter");
  365. #endif
  366.  
  367.     if ((ptr = get_node(cb)) == NULL)
  368.         return (-1);
  369.  
  370.     ptr->next = (cb->tab)[i = (*(cb->hashfunc))(s,cb->size)];
  371.     (cb->tab)[i] = ptr;
  372.     ptr->key = s;
  373.     ptr->data = data;
  374.     return (0);
  375. }
  376.  
  377. /*
  378. ** Routine to scan all hash table entries through successive calls.
  379. ** Returns 1 if an entry found, 0 for no more entries.  Will not
  380. ** be returned in any particular order comprehensible to the
  381. ** calling program (hash table order).
  382. **
  383. **    tab - table pointer from htab_init
  384. **    first - 1 to start scan, 0 on succesive calls.
  385. **    data, key - returned data and key.
  386. **
  387. ** Precautions have been taken to allow interleave of this routine with
  388. ** htab_del and htab_clear, but the only interleave that truly makes
  389. ** sense is to selectively htab_del() entries on some basis as they
  390. ** come back from htab_list().  htab_enter()'s in mid list scan may be
  391. ** done, but they may or may not show up on following calls, dependent
  392. ** on where they were entered in relation to the current list pointer.
  393. **
  394. ** This routine sets a global variable on all successful calls:
  395. **
  396. **    int Htab_Index; hash table index entry was found at.
  397. **
  398. ** By examining this while scanning the list of entries, a caller may
  399. ** obtain statistics on table distribution.  The value will increase
  400. ** monotonically as the search proceeds, skipping across indices
  401. ** with no entries.
  402. */
  403.  
  404. int Htab_Index;
  405.  
  406. htab_list(tab,first,data,key)
  407. char *tab;
  408. int first;
  409. char **data;
  410. char **key;
  411. {
  412.     register CONTEXT *cb;
  413.  
  414.     cb = (CONTEXT *) tab;
  415.  
  416. #ifdef HASHMAGIC
  417.     MAGCHECK(cb,"htab_list");
  418. #endif
  419.  
  420.     if (first)
  421.     {
  422.         cb->srch = NULL;
  423.         cb->srchidx = -1;
  424.     }
  425.  
  426.     while (cb->srch == NULL)
  427.     {
  428.         ++(cb->srchidx);
  429.         if (cb->srchidx >= cb->size)
  430.             return (0);
  431.         cb->srch = (cb->tab)[cb->srchidx];
  432.     }
  433.  
  434.     Htab_Index = cb->srchidx;
  435.  
  436.     *data = (cb->srch)->data;
  437.     *key = (cb->srch)->key;
  438.  
  439.     cb->srch = (cb->srch)->next;
  440.     return(1);
  441. }
  442.  
  443. static HASHTAB *
  444. get_node(cb)
  445. CONTEXT *cb;
  446. {
  447.     char *addr;
  448.     HASHTAB *ptr;
  449.     int i;
  450.  
  451.     if (cb->tpool == NULL)
  452.     {
  453.         addr = malloc((cb->ablock)*sizeof(HASHTAB)+sizeof(FADDR));
  454.         if (addr == NULL)
  455.         {
  456.             (*(cb->afail))();
  457.             return (NULL);
  458.         }
  459.  
  460.         ((FADDR *) addr)->next = cb->fpool;
  461.         cb->fpool = (FADDR *) addr;
  462.         addr += sizeof(FADDR);
  463.         cb->tpool = (HASHTAB *) addr;
  464.         for (i=1; i < cb->ablock; ++i)
  465.             (cb->tpool)[i-1].next = cb->tpool + i;
  466.         (cb->tpool)[i-1].next = NULL;
  467.  
  468.         if (cb->ablock < ALLOCLIMIT)
  469.             cb->ablock *= 2;
  470.     }
  471.  
  472.     ptr = cb->tpool;
  473.     cb->tpool = (cb->tpool)->next;
  474.     return (ptr);
  475. }
  476.  
  477. static int
  478. hash(s,size)
  479. register char *s;
  480. int size;
  481. {
  482.     register long rem;
  483.  
  484.     for (rem = 0; *s != '\0'; ++s)
  485.         rem = (rem * 128 + *s) % size;
  486.     return(rem);
  487. }
  488.  
  489. static int
  490. def_afail()
  491. {
  492.     fatal("memory allocation failure in hash table routines");
  493. }
  494.