home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / nfsd / src / hashtable.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-29  |  5.4 KB  |  232 lines

  1. /*  Routines to manage hash tables
  2.  
  3.     ©1999 Joseph Walton
  4.  
  5.     This software is distributed under the terms of the GNU General Public
  6.     License; either version 2 of the License, or (at your option) any
  7.     later version.
  8. */
  9.  
  10. /*
  11.     Many features are currently commented out - they're not being used
  12.      at the moment.
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include "hashtable.h"
  20. #include "nfsd.h"
  21. #include "memory.h"
  22.  
  23. struct HashTable {
  24.     HashFunc ht_HashFunc;
  25.     EqualsFunc ht_EqualsFunc;
  26.     LONG ht_NumEntries;
  27.     LONG ht_NumBuckets;
  28.     struct Entry **ht_Table;
  29. };
  30.  
  31. struct Entry {
  32.     ULONG e_HashCode;
  33.     APTR e_Key;
  34.     APTR e_Data;
  35.     struct Entry *e_Next;
  36. };
  37.  
  38. #define ALLOCTABLE(n) ((struct Entry **)AllocVecPooled((n) * sizeof(struct Entry *)))
  39. #define CLEARTABLE(t, n) (memset((t), 0, sizeof(struct Entry *) * (n)))
  40. #define BUCKETFOR(ht,c) ((ht)->ht_Table[(c) % (ht)->ht_NumBuckets])
  41. #define MIN_SIZE 11
  42.  
  43. static void insertEntry(struct HashTable *ht, struct Entry *e);
  44. static void resizeTable(struct HashTable *ht);
  45.  
  46. struct HashTable *htMakeNew(HashFunc hf, EqualsFunc ef)
  47. {
  48.     struct HashTable *ht = (struct HashTable *)AllocVecPooled(sizeof(struct HashTable));
  49.     if (ht) {
  50.         ht->ht_HashFunc = hf;
  51.         ht->ht_EqualsFunc = ef;
  52.         ht->ht_NumEntries = 0;
  53.         ht->ht_NumBuckets = MIN_SIZE;
  54.         ht->ht_Table = ALLOCTABLE(MIN_SIZE);
  55.         if (ht->ht_Table) {
  56.             CLEARTABLE(ht->ht_Table, MIN_SIZE);
  57.             return ht;
  58.         }
  59.         FreeVecPooled(ht);
  60.     }
  61.     return NULL;
  62. }
  63.  
  64. /* I never explicitly free the hashtables I'm using - the mempools
  65.     take care of this.
  66.  
  67. void htFree(struct HashTable *ht, DataFreeFunc dff)
  68. {
  69.     int i;
  70.     for (i = 0 ; i < ht->ht_NumBuckets ; i++) {
  71.         struct Entry *e = BUCKETFOR(ht, i);
  72.         while (e) {
  73.             struct Entry *next = e->e_Next;
  74.             if (dff)
  75.                 dff(e->e_Data);
  76.             FreeVecPooled(e);
  77.             e = next;
  78.         }
  79.     }
  80.     FreeVecPooled(ht->ht_Table);
  81.     FreeVecPooled(ht);
  82. }
  83. */
  84.  
  85. BOOL htAdd(struct HashTable *ht, APTR key, APTR data)
  86. {
  87.     struct Entry *e = (struct Entry *)AllocVecPooled(sizeof(struct Entry));
  88.     if (e) {
  89.         ULONG hashCode = ht->ht_HashFunc(key);
  90.  
  91.         e->e_HashCode = hashCode;
  92.         e->e_Key = key;
  93.         e->e_Data = data;
  94.  
  95.         insertEntry(ht, e);
  96.         resizeTable(ht);
  97.  
  98.         return TRUE;
  99.     }
  100.     return FALSE;
  101. }
  102.  
  103. static void insertEntry(struct HashTable *ht, struct Entry *e)
  104. {
  105.     struct Entry **list;
  106.     list = &BUCKETFOR(ht, e->e_HashCode);
  107.     e->e_Next = *list;
  108.     *list = e;
  109.     ht->ht_NumEntries++;
  110. }
  111.  
  112. static void resizeTable(struct HashTable *ht)
  113. {
  114.     /* Is it outside reasonable bounds? */
  115.     int size = ht->ht_NumBuckets,
  116.         entries = ht->ht_NumEntries;
  117.  
  118.     if (((entries > MIN_SIZE) && (entries < (size / 3))) || (entries > (3 * size))) {
  119.         struct Entry **newTable;
  120.         int newSize = entries | 1; /* Make it odd, just for luck */
  121.  
  122. /*
  123.         printf("Outside reasonable range. Is %d, should be %d\n", size, newSize);
  124.         printf("before: avg = %f, sd = %f\n",
  125.                (float)ht->ht_NumEntries / (float)ht->ht_NumBuckets,
  126.                getStdDev(ht));
  127. */
  128.  
  129.         newTable = ALLOCTABLE(newSize);
  130.         if (newTable) {
  131.             struct Entry **oldTable = ht->ht_Table;
  132.             int oldSize = ht->ht_NumBuckets;
  133.             int i;
  134.  
  135.             CLEARTABLE(newTable, newSize);
  136.             ht->ht_NumEntries = 0;
  137.             ht->ht_Table = newTable;
  138.             ht->ht_NumBuckets = newSize;
  139.  
  140.             /* Move over all the entries */
  141.             for (i = 0 ; i < oldSize ; i++) {
  142.                 struct Entry *e = oldTable[i];
  143.                 while (e) {
  144.                     struct Entry *next = e->e_Next;
  145.                     insertEntry(ht, e);
  146.                     e = next;
  147.                 }
  148.             }
  149.             FreeVecPooled(oldTable);
  150.             DEBUG(puts("Hashtable size succesfully changed"));
  151.         }
  152. /*
  153.         printf("after: avg = %f, sd = %f\n",
  154.             (float)ht->ht_NumEntries / (float)ht->ht_NumBuckets,
  155.             getStdDev(ht));
  156. */
  157.     }
  158. }
  159.  
  160. APTR htGet(struct HashTable *ht, APTR key)
  161. {
  162.     struct Entry *e;
  163.     ULONG hashCode;
  164.  
  165.     hashCode = ht->ht_HashFunc(key);
  166.  
  167.     e = BUCKETFOR(ht, hashCode);
  168.  
  169.     while (e) {
  170.         if (ht->ht_EqualsFunc(key, e->e_Key)) {
  171.             return e->e_Data;
  172.         }
  173.         e = e->e_Next;
  174.     }
  175.     return NULL;
  176. }
  177.  
  178. APTR htRemove(struct HashTable *ht, APTR key)
  179. {
  180.     struct Entry **e;
  181.     ULONG hashCode;
  182.  
  183.     hashCode = ht->ht_HashFunc(key);
  184.     e = &BUCKETFOR(ht, hashCode);
  185.  
  186.     while (*e) {
  187.         if (ht->ht_EqualsFunc(key, (*e)->e_Key)) {
  188.             struct Entry *must_go = *e;
  189.             APTR data = must_go->e_Data;
  190.  
  191.             *e = (*e)->e_Next;
  192.             FreeVecPooled(must_go);
  193.             ht->ht_NumEntries--;
  194.             resizeTable(ht);
  195.  
  196.             return data;
  197.         }
  198.         e = &(*e)->e_Next;
  199.     }
  200.     return NULL;
  201. }
  202.  
  203. int htGetSize(struct HashTable *ht)
  204. {
  205.     return ht->ht_NumEntries;
  206. }
  207.  
  208. /* Gather some statistics
  209.  
  210. #include <math.h>
  211. double getStdDev(struct HashTable *ht)
  212. {
  213.     struct Entry *e;
  214.     int i;
  215.     double avgLength = (float)ht->ht_NumEntries / (float)ht->ht_NumBuckets;
  216.     double sum = 0.0;
  217.  
  218.     for (i = 0 ; i < ht->ht_NumBuckets ; i++) {
  219.         int l = 0;
  220.         e = BUCKETFOR(ht, i);
  221.         while (e) {
  222.             l++;
  223.             e = e->e_Next;
  224.         }
  225.  
  226.         sum += (avgLength - (double)l) * (avgLength - (double)l);
  227.     }
  228.  
  229.     return sqrt(sum / (double)ht->ht_NumBuckets);
  230. }
  231. */
  232.