home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / xp / xp_hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.7 KB  |  576 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "xp_hash.h"
  21. #include "xp.h"
  22.  
  23. #ifdef PROFILE
  24. #pragma profile on
  25. #endif
  26.  
  27. /*
  28.  * XP_StringHash() is from:
  29.  * Aho, Sethi, and Ullman, "Compilers - Principles, Techniques, and Tools",
  30.  * (the Dragon book), p436, hashpjw() by Peter J. Weinberger.
  31.  * Permission has been kindly granted by Mr Weinberger to release this
  32.  * function as part of the Mozilla public release.
  33.  */
  34. PUBLIC uint32
  35. XP_StringHash (const void *xv)
  36.   register uint32 h = 0;
  37.   register uint32 g;
  38.   register unsigned const char *x = (unsigned const char *) xv;
  39.  
  40.   assert(xv);
  41.  
  42.   if (!x) return 0;
  43.  
  44.   while (*x != 0)
  45.   {
  46.     h = (h << 4) + *x++;
  47.     if ((g = h & 0xf0000000) != 0)
  48.       h = (h ^ (g >> 24)) ^ g;
  49.   }
  50.  
  51.   return h;
  52. }
  53.  
  54. /*    phong's linear congruential hash  */
  55. uint32
  56. XP_StringHash2 (const char *ubuf)
  57. {
  58.     unsigned char * buf = (unsigned char*) ubuf;
  59.     uint32 h=1;
  60.     while(*buf)
  61.     {
  62.         h = 0x63c63cd9*h + 0x9c39c33d + (int32)*buf;
  63.         buf++;
  64.     }
  65.     return h;
  66. }
  67.  
  68.  
  69.  
  70. /* Hash tables.  For sure this time.
  71.  
  72.    These tables consist of a fixed number of buckets containing linked lists.
  73.    The number of buckets is forced to be prime.  Links in the buckets are
  74.    in no particular order.
  75.  
  76.    Since each link in the bucket is a seperate malloc'ed block, that incurs
  77.    nontrivial overhead; a more memory efficient model would have us avoid
  78.    colisions and enlarge and rehash the table when it got tight, but that
  79.    requires the table cells to be contiguous in memory, andw ith large
  80.    tables, that could get to be a problem, because of memory fragmentation.
  81.    So it's probably better to use many small mallocs.
  82.  
  83.    In hash tables, comparison function is used only as an equality test, not
  84.    an ordering test.  Hash lists use the order, but I don't see a benefit to
  85.    keeping links in the buckets ordered.
  86.  */
  87.  
  88. struct xp_HashTable
  89. {
  90.   XP_HashingFunction  hash_fn;
  91.   XP_HashCompFunction compare_fn;
  92.   uint32 size;
  93.   struct xp_HashBucket **buckets;
  94. };
  95.  
  96. struct xp_HashBucket
  97. {
  98.   const void *key;
  99.   void *value;
  100.   struct xp_HashBucket *next;
  101. };
  102.  
  103.  
  104. static const uint32 primes[] = {
  105.   /* 3, 7, 11, 13, 29, 37, 47, */ 59, 71, 89, 107, 131, 163, 197, 239, 293,
  106.   353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371,
  107.   4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, 25229,
  108.   30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
  109.   187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
  110.   968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249 };
  111.  
  112.  
  113. static uint32
  114. toprime (uint32 size)
  115. {
  116.   register unsigned int i;
  117.   static unsigned int s = (sizeof (primes) / sizeof (*primes)) - 1;
  118.   for (i = 0; i < s; i++)
  119.     /* Return the smallest prime larger than SIZE, but don't return a
  120.        prime such that allocating an array of that many pointers will
  121.        allocate a block larger than 64k.  The toy computers can't do it,
  122.        and all platforms will assert().
  123.      */
  124.     if (size <= primes[i] ||
  125.         ((primes[i+1] * sizeof(void *)) >= 64000))
  126.       return primes[i];
  127.   return primes[s-1];
  128. }
  129.  
  130.  
  131. /* Create a new, empty hash table object.
  132.  */
  133. PUBLIC XP_HashTable
  134. XP_HashTableNew (uint32 size, 
  135.                  XP_HashingFunction  hash_fn, 
  136.                  XP_HashCompFunction compare_fn)
  137. {
  138.   struct xp_HashTable *table = XP_NEW (struct xp_HashTable);
  139.   if (!table) return 0;
  140.   table->hash_fn = hash_fn;
  141.   table->compare_fn = compare_fn;
  142.  
  143.   table->size = toprime (size);
  144.   table->buckets = (struct xp_HashBucket **)
  145.     XP_CALLOC (table->size, sizeof (struct xp_HashBucket *));
  146.   if (!table->buckets)
  147.     {
  148.       XP_FREE (table);
  149.       return 0;
  150.     }
  151.   return table;
  152. }
  153.  
  154. /* Remove all entries from the hash table.
  155.  */
  156. PUBLIC void
  157. XP_Clrhash (XP_HashTable table)
  158. {
  159.   XP_ASSERT (table);
  160.   if (!table)
  161.     return;
  162.  
  163.   XP_ASSERT (table->buckets);
  164.   if (table->buckets)
  165.     {
  166.       uint32 i;
  167.       struct xp_HashBucket *bucket, *next;
  168.       for (i = 0; i < table->size; i++)
  169.         for (bucket = table->buckets[i], next = bucket ? bucket->next : 0;
  170.              bucket;
  171.              bucket = next, next = bucket ? bucket->next : 0)
  172.           XP_FREE (bucket);
  173.       XP_MEMSET (table->buckets, 0, table->size * sizeof (*table->buckets));
  174.     }
  175. }
  176.  
  177.  
  178. /* Clear and free the hash table.
  179.  */
  180. PUBLIC void
  181. XP_HashTableDestroy (XP_HashTable table)
  182. {
  183.   XP_ASSERT (table);
  184.   if (!table)
  185.     return;
  186.   XP_Clrhash (table);
  187.   XP_ASSERT (table->buckets);
  188.   if (table->buckets)
  189.     XP_FREE (table->buckets);
  190.   XP_FREE (table);
  191. }
  192.  
  193. /* Add an association between KEY and VALUE to the hash table.
  194.    An existing association will be replaced.
  195.    (Note that 0 is a legal value.)
  196.    This can only fail if we run out of memory.
  197.  */
  198. PUBLIC int
  199. XP_Puthash (XP_HashTable table, const void *key, void *value)
  200. {
  201.   register uint32 bucket_num;
  202.   register struct xp_HashBucket *bucket, *prev;
  203.   XP_ASSERT (table);
  204.   if (! table) return -1;
  205.  
  206.   bucket_num = ((*table->hash_fn) (key)) % table->size;
  207.  
  208.   /* Iterate over all entries in this bucket.
  209.    */
  210.   for (prev = 0, bucket = table->buckets [bucket_num];
  211.        bucket;
  212.        prev = bucket, bucket = bucket->next)
  213.  
  214.     if (key == bucket->key ||
  215.         0 == (*table->compare_fn) (key, bucket->key))  /* We have a winner! */
  216.       {
  217.         bucket->value = value;
  218.         return 0;
  219.       }
  220.  
  221.   /* If we get here, there was no entry for this key in the table.
  222.    */
  223.   bucket = XP_NEW (struct xp_HashBucket);
  224.   if (! bucket)
  225.     return -1;
  226.  
  227.   bucket->key = key;
  228.   bucket->value = value;
  229.   bucket->next = 0;
  230.  
  231.   if (prev)
  232.     /* If prev has a value, it is the last bucket entry in the chain. */
  233.     prev->next = bucket;
  234.   else
  235.     table->buckets [bucket_num] = bucket;
  236.  
  237.   return 0;
  238. }
  239.  
  240. /* Remove the for KEY in the table, if it exists.
  241.    Returns FALSE if the key wasn't in the table.
  242.  */
  243. PUBLIC XP_Bool
  244. XP_Remhash (XP_HashTable table, const void *key)
  245. {
  246.   register uint32 bucket_num;
  247.   register struct xp_HashBucket *bucket, *prev;
  248.   XP_ASSERT (table);
  249.   if (! table) return -1;
  250.  
  251.   bucket_num = ((*table->hash_fn) (key)) % table->size;
  252.  
  253.   /* Iterate over all entries in this bucket.
  254.    */
  255.   for (prev = 0, bucket = table->buckets [bucket_num];
  256.        bucket;
  257.        prev = bucket, bucket = bucket->next)
  258.  
  259.     if (key == bucket->key ||
  260.         0 == (*table->compare_fn) (key, bucket->key))  /* We have a winner! */
  261.       {
  262.         if (prev)
  263.           prev->next = bucket->next;
  264.         else
  265.           table->buckets [bucket_num] = bucket->next;
  266.         XP_FREE (bucket);
  267.         return TRUE;
  268.       }
  269.  
  270.   return FALSE;
  271. }
  272.  
  273.  
  274. /* Looks up KEY in the table and returns the corresponding value.
  275.    If KEY is not in the table, `default_value' will be returned instead.
  276.    (This is necessary since 0 is a valid value with which a key can be
  277.    associated.)
  278.  */
  279. PUBLIC void *
  280. XP_Gethash (XP_HashTable table, const void *key, void *default_value)
  281. {
  282.   register uint32 bucket_num;
  283.   register struct xp_HashBucket *bucket;
  284.   XP_ASSERT (table);
  285.   if (! table) return default_value;
  286.  
  287.   bucket_num = ((*table->hash_fn) (key)) % table->size;
  288.   for (bucket = table->buckets [bucket_num]; bucket; bucket = bucket->next)
  289.     if (key == bucket->key ||
  290.         0 == (*table->compare_fn) (key, bucket->key))  /* We have a winner! */
  291.       return bucket->value;
  292.  
  293.   return default_value;
  294. }
  295.  
  296.  
  297. static void
  298. xp_maphash (XP_HashTable table, XP_HashTableMapper mapper, void *closure,
  299.             XP_Bool remhash_p)
  300. {
  301.   struct xp_HashBucket *bucket, *next;
  302.   uint32 i;
  303.   XP_ASSERT (table);
  304.   XP_ASSERT (mapper);
  305.   if (!table || !mapper) return;
  306.   /* map over buckets. */
  307.   for (i = 0; i < table->size; i++)
  308.     /* map over bucket entries.  Remember the "next" pointer in case
  309.        remhash is called. */
  310.     for (bucket = table->buckets[i], next = bucket ? bucket->next :0;
  311.          bucket;
  312.          bucket = next, next = bucket ? bucket->next : 0)
  313.       {
  314.         /* Call the mapper, and terminate early if it returns FALSE.
  315.            After calling the mapper, but before returning, free and
  316.            unlink the bucket if we're in remhash-mode.
  317.          */
  318.         XP_Bool status = (*mapper) (table, bucket->key, bucket->value,closure);
  319.         if (remhash_p)
  320.           {
  321.             XP_FREE (bucket);
  322.             /* It always becomes the top of the list, since we've freed
  323.                the others. */
  324.             table->buckets [i] = next;
  325.           }
  326.         if (status == FALSE)
  327.           return;
  328.       }
  329. }
  330.  
  331.  
  332. /* Apply a function to each pair of elements in the hash table.
  333.    If that function returns FALSE, then the mapping stops prematurely.
  334.    The mapping function may call XP_Remhash() on the *current* key, but
  335.    not on any other key in this table.  It also may not clear or destroy
  336.    the table.
  337.  */
  338. PUBLIC void
  339. XP_Maphash (XP_HashTable table, XP_HashTableMapper mapper, void *closure)
  340. {
  341.   xp_maphash (table, mapper, closure, FALSE);
  342. }
  343.  
  344. /* Apply a function to each pair of elements in the hash table.
  345.    After calling the function, that pair will be removed from the table.
  346.    If the function returns FALSE, then the mapping stops prematurely.
  347.    Any items which were not mapped over will still remain in the table,
  348.    but those items which were mapped over will have been freed.
  349.  
  350.    This could also be done by having the mapper function unconditionally
  351.    call XP_Remhash(), but using this function will be slightly more efficient.
  352.  */
  353. PUBLIC void
  354. XP_MapRemhash (XP_HashTable table, XP_HashTableMapper mapper, void *closure)
  355. {
  356.   xp_maphash (table, mapper, closure, TRUE);
  357. }
  358.  
  359.  
  360.  
  361. /* create a hash list, which isn't really a table.
  362.  */
  363. PUBLIC XP_HashList *
  364. XP_HashListNew (int size, 
  365.                   XP_HashingFunction  hash_func, 
  366.                   XP_HashCompFunction comp_func)
  367. {
  368.     XP_HashList * hash_struct = XP_NEW(XP_HashList);
  369.     XP_List **hash_list;
  370.     int new_size;
  371.  
  372.     if(!hash_struct)
  373.         return(NULL);
  374.  
  375.     new_size = toprime (size);
  376.     XP_ASSERT (new_size >= size);
  377.  
  378.     hash_list = (XP_List **) XP_ALLOC(sizeof(XP_List *) * new_size);
  379.  
  380.     if(!hash_list)
  381.       {
  382.         XP_FREE(hash_struct);
  383.         return(NULL);
  384.       }
  385.  
  386.     /* zero out the list
  387.      */
  388.     XP_MEMSET(hash_list, 0, sizeof(XP_List *) * new_size);
  389.  
  390.     hash_struct->list          = hash_list;
  391.     hash_struct->size          = new_size;
  392.     hash_struct->hash_func     = hash_func;
  393.     hash_struct->comp_func     = comp_func;
  394.     
  395.     return(hash_struct);
  396. }
  397.  
  398. /* free a hash list, which isn't really a table.
  399.  */
  400. PUBLIC void
  401. XP_HashListDestroy (XP_HashList * hash_struct)
  402. {
  403.     if(!hash_struct)
  404.        return;
  405.  
  406.     XP_FREE(hash_struct->list);
  407.     XP_FREE(hash_struct);
  408. }
  409.  
  410. /* add an element to a hash list, which isn't really a table.
  411.  *
  412.  * returns positive on success and negative on failure
  413.  *
  414.  * ERROR return codes
  415.  *
  416.  *  XP_HASH_DUPLICATE_OBJECT
  417.  */
  418. PUBLIC int
  419. XP_HashListAddObject (XP_HashList * hash_struct, void * new_ele)
  420. {
  421.     uint32   bucket_num;
  422.     int      result;
  423.     XP_List * list_ptr;
  424.     void   * obj_ptr;
  425.  
  426.     if(!hash_struct)
  427.        return -1;
  428.  
  429.     /* get an integer from the hashing function 
  430.      */
  431.     bucket_num = (*hash_struct->hash_func)(new_ele);
  432.  
  433.     /* adjust the integer to the size of the hash table
  434.      */
  435.     bucket_num = bucket_num % hash_struct->size;
  436.  
  437.     list_ptr = hash_struct->list[bucket_num];
  438.  
  439.     if(!list_ptr)
  440.       {
  441.         list_ptr = XP_ListNew();
  442.     
  443.         if(!list_ptr)
  444.             return -1;
  445.  
  446.         hash_struct->list[bucket_num] = list_ptr;
  447.       }
  448.  
  449.     /* run through the list and find an object that returns
  450.      * greater than 0 when compared
  451.      */
  452.     while((obj_ptr = XP_ListNextObject(list_ptr)) != 0)
  453.       {
  454.         result = (*hash_struct->comp_func)(obj_ptr, new_ele);
  455.         if(result > -1)
  456.            break;
  457.       }
  458.  
  459.     if(obj_ptr && result == 0)
  460.       {
  461.         /* the objects are the same!
  462.          */
  463.         return(XP_HASH_DUPLICATE_OBJECT);
  464.       }
  465.  
  466.     if(obj_ptr)
  467.       {
  468.         /* insert right before the obj_ptr 
  469.          */
  470.         XP_ListInsertObject(hash_struct->list[bucket_num], obj_ptr, new_ele);
  471.       }
  472.     else
  473.       {
  474.         /* it's either the first element to go into the list
  475.          * or it is the last by comparison
  476.          */
  477.         XP_ListAddObjectToEnd(hash_struct->list[bucket_num], new_ele);
  478.       }
  479.  
  480.     return 0; /* #### what should return value be? */
  481. }
  482.  
  483. /* finds an object by name in the hash list, which isn't really a table.
  484.  */
  485. PUBLIC void *
  486. XP_HashListFindObject (XP_HashList * hash_struct, void * ele)
  487. {
  488.     uint32   bucket_num;
  489.     int      result;
  490.     XP_List * list_ptr;
  491.     void   * obj_ptr;
  492.  
  493.     if(!hash_struct)
  494.        return(NULL);
  495.  
  496.     /* get an integer from the hashing function
  497.      */
  498.     bucket_num = (*hash_struct->hash_func)(ele);
  499.  
  500.     /* adjust the integer to the size of the hash table
  501.      */
  502.     bucket_num = bucket_num % hash_struct->size;
  503.  
  504.     list_ptr = hash_struct->list[bucket_num];
  505.  
  506.     /* run through the list and find the object
  507.      */
  508.     while((obj_ptr = XP_ListNextObject(list_ptr)) != 0)
  509.       {
  510.         result = (*hash_struct->comp_func)(obj_ptr, ele);
  511.  
  512.         if(result == 0)
  513.            return(obj_ptr);
  514.  
  515.         if(result > 0)
  516.            return(NULL);
  517.  
  518.       }
  519.  
  520.     return(NULL);
  521. }
  522.  
  523. /* removes an object by name from the hash list, which isn't really a table,
  524.  * and returns the object if found
  525.  */
  526. PUBLIC void *
  527. XP_HashListRemoveObject (XP_HashList * hash_struct, void * ele)
  528. {
  529.     uint32   bucket_num;
  530.     int      result;
  531.     XP_List * list_ptr;
  532.     void   * obj_ptr;
  533.  
  534.     if(!hash_struct || !ele)
  535.        return(NULL);
  536.  
  537.     /* get an integer from the hashing function
  538.      */
  539.     bucket_num = (*hash_struct->hash_func)(ele);
  540.  
  541.     /* adjust the integer to the size of the hash table
  542.      */
  543.     bucket_num = bucket_num % hash_struct->size;
  544.  
  545.     list_ptr = hash_struct->list[bucket_num];
  546.  
  547.     /* run through the list and find the object
  548.      */
  549.     while((obj_ptr = XP_ListNextObject(list_ptr)) != 0)
  550.       {
  551.         result = (*hash_struct->comp_func)(obj_ptr, ele);
  552.  
  553.         if(result == 0)
  554.           {
  555.             XP_ListRemoveObject(hash_struct->list[bucket_num], obj_ptr);
  556.  
  557. /* ALEKS. Bucket needs to be freed here if there are no more objects in it*/
  558.             if (hash_struct->list[bucket_num]->next == NULL)
  559.             {
  560.                 XP_ListDestroy(hash_struct->list[bucket_num]);
  561.                 hash_struct->list[bucket_num] = NULL;
  562.             }
  563.             return(obj_ptr);
  564.           }
  565.         
  566.         if(result > 0)
  567.            return(NULL);
  568.       }
  569.     return(NULL);
  570. }
  571.  
  572. #ifdef PROFILE
  573. #pragma profile on
  574. #endif
  575.