Advertisement
Guest User

Untitled

a guest
Jun 27th, 2017
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.74 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2010 spy
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. The name of the author may not be used to endorse or promote products
  14.  *    derived from this software without specific prior written permission.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19.  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  20.  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  24.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  25.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26.  * POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28. /*
  29.  * Dynamic hash tables.
  30.  *
  31.  * As usual, nodes with colliding hashes are doubly-linked in a list.
  32.  * However, these hash tables will automatically grow as they become
  33.  * full (they don't shrink back), so to simplify rehashing those lists
  34.  * of nodes are maintained as parts of a super-list containing all
  35.  * nodes in a table. The end of a particular sub-list is not marked in
  36.  * any way, but the very hashes serve to that purpose. Except for the
  37.  * sub-lists, there's no order in the super-list. Refer to the scheme:
  38.  *
  39.  *                 ...+-------+...+-------+...+-------+...+-------+...
  40.  *      .t_table:     |  811  |   | 14023 |   | 19588 |   | 28706 |
  41.  *                 ...+-------+...+-------+...+-------+...+-------+...
  42.  *                        :           :           :           :
  43.  *                        v           v           v           v
  44.  *                      +---+       +---+       +---+       +---+
  45.  *      .t_nodes:  ---->| A |------>| B |     ->| D |     ->| F |....>
  46.  *                      +---+       +---+    /  +---+    /  +---+
  47.  *                                    |     /     |     /
  48.  *                                    v    /      v    /
  49.  *                                  +---+ /     +---+ /
  50.  *                                  | C |-      | E |-
  51.  *                                  +---+       +---+
  52.  */
  53. #include "hash.h"
  54. #include "var.h"
  55. #include <assert.h>
  56. #include <ctype.h>
  57. #include <errno.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <strings.h>
  61. #include <sys/types.h>
  62. #include <syslog.h>
  63.  
  64. /*
  65.  * Internal functions.
  66.  */
  67.  
  68. /*
  69.  * Bitwise hash function.  Author J. Zobel, April 2001.
  70.  * Permission to use this code is freely granted,
  71.  * provided that this statement is retained.
  72.  */
  73. static int
  74. zobel_hash(hash_table_t *tp, const char *key)
  75. {
  76.     int digest = tp->t_salt;
  77.  
  78.     while (*key)
  79.         digest ^= (digest << 5) + (digest >> 2) +
  80.             (tp->t_nocase ? tolower(*key++) : *key++);
  81.     return (digest % tp->t_size);
  82. }
  83.  
  84. static int
  85. realloc_hash_table(hash_table_t *tp, size_t nelem)
  86. {
  87.     hash_node_t *ntp;
  88.  
  89.     assert(nelem);
  90.     if (!(ntp = calloc(nelem, sizeof (*tp->t_table)))) {
  91.         syslog(LOG_ERR,
  92.     "realloc_hash_table(): calloc() of %i bytes failed (error %i: %s)",
  93.                nelem * sizeof (*tp->t_table), errno, strerror(errno));
  94.         return (-1);
  95.     }
  96.     if (tp->t_table)
  97.         free(tp->t_table);
  98.     tp->t_table = ntp;
  99.     tp->t_size = nelem;
  100.     tp->t_nelem = 0;
  101.     return (0);
  102. }
  103.  
  104. static void
  105. grow_hash_table(hash_table_t *tp)
  106. {
  107.     size_t oldsize;
  108.  
  109.     oldsize = tp->t_size;
  110.     /**
  111.      * todo: configurable per-table growth factors
  112.      */
  113.     (void)realloc_hash_table(tp, (size_t)((float)tp->t_size * 1.30f));
  114.     hash_table_rehash(tp, rand());
  115.     syslog(LOG_INFO, "resized hash table %s from %i to %i", tp->t_name,
  116.            oldsize, tp->t_size);
  117. }
  118.  
  119. static void
  120. insert_node(hash_table_t *tp, hash_node_t *np, hash_node_t **nnpp)
  121. {
  122.     if (*nnpp) {
  123.         np->n_prev = (*nnpp)->n_prev;
  124.         (*nnpp)->n_prev = np;
  125.         if (np->n_prev)
  126.             np->n_prev->n_next = np;
  127.         else {
  128.             assert(tp->t_nodes == *nnpp);
  129.             tp->t_nodes = np;
  130.         }
  131.         np->n_next = *nnpp;
  132.     } else {
  133.         np->n_prev = NULL;
  134.         np->n_next = tp->t_nodes;
  135.         tp->t_nodes = np;
  136.     }
  137.     *nnpp = np;
  138. }
  139.  
  140. /*
  141.  * Exported functions.
  142.  */
  143.  
  144. /**
  145.  * todo: salt param
  146.  */
  147. void
  148. hash_init(hash_table_t *tp, const char *name, size_t off, size_t size,
  149.       boolean_t nocase)
  150. {
  151.     assert(name);
  152.     assert(size);
  153.     tp->t_name = name;
  154.     tp->t_off = off;
  155.     tp->t_nocase = nocase;
  156.     tp->t_salt = rand();
  157.     tp->t_nodes = NULL;
  158.     if (realloc_hash_table(tp, size)) {
  159.         syslog(LOG_EMERG,
  160.     "hash_init(): panic: failed to allocate memory for hash table %s",
  161.                name);
  162.         abort();
  163.     }
  164. }
  165.  
  166. void
  167. hash_fini(hash_table_t *tp)
  168. {
  169.     assert(tp);
  170.     assert(tp->t_table);
  171.     free(tp->t_table);
  172. }
  173.  
  174. void
  175. hash_node_init(hash_node_t *np, const char *key)
  176. {
  177.     assert(np);
  178.     assert(key);
  179.     np->n_key = key;
  180.     np->n_next = np->n_pprev = NULL;
  181. }
  182.  
  183. void
  184. hash_table_rehash(hash_table_t *tp, int salt)
  185. {
  186.     hash_node_t *np, *walker;
  187.  
  188.     assert(tp);
  189.     tp->t_salt = salt;
  190.     walker = tp->t_nodes;
  191.     while (walker) {
  192.         np = walker;
  193.         walker = walker->n_next;
  194.         hash_insert(tp, np);
  195.     }
  196. }
  197.  
  198. void
  199. hash_insert(hash_table_t *tp, hash_node_t *np)
  200. {
  201.     assert(tp);
  202.     assert(np);
  203.     assert(tp->t_nelem < tp->t_size);
  204.     if (++tp->t_nelem == tp->t_size)
  205.         grow_hash_table(tp);
  206.     insert_node(tp, np, &tp->t_table[zobel_hash(tp, np->n_key)]);
  207. }
  208.  
  209. void
  210. hash_remove(hash_table_t *tp, hash_node_t *np)
  211. {
  212.     int digest;
  213.  
  214.     assert(tp);
  215.     assert(np);
  216.     digest = zobel_hash(tp, np->n_key);
  217.     if (tp->t_table[digest] == np)
  218.         tp->t_table[digest] = np->n_next;
  219.     if (np->n_next)
  220.         np->n_next->n_prev = np->n_prev;
  221.     if (tp->t_nodes == np) {
  222.         assert(!np->n_prev);
  223.         tp->t_nodes = np->n_next;
  224.     } else {
  225.         assert(np->n_prev);
  226.         np->n_prev->n_next = np->n_next;
  227.     }
  228.     --tp->t_nelem;
  229. }
  230.  
  231. void *
  232. hash_find(hash_table_t *tp, const char *key)
  233. {
  234.     hash_node_t *np;
  235.     int digest;
  236.  
  237.     assert(tp);
  238.     assert(key);
  239.     digest = zobel_hash(tp, key);
  240.     for (np = table->t_table[digest];
  241.          np && zobel_hash(np->n_key, tp->t_size) == digest;
  242.          np = np->n_next)
  243.         if (tp->t_nocase ? !strcasecmp(key, np->n_key) :
  244.             !strcmp(key, np->n_key)) {
  245.             if (*np->n_prev != &tp->t_table[digest]) {
  246.                 hash_remove(tp, np);
  247.                 insert_node(tp, np, &tp->t_table[digest]);
  248.             }
  249.             return (np - tp->t_off);
  250.         }
  251.     return (NULL);
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement