Advertisement
avp210159

ghash.h hashtable multimap

Mar 23rd, 2015
594
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.04 KB | None | 0 0
  1. // avp 2015 simple multiset hash key:value  resolve collisions by LIFO chaining
  2. #ifndef _GHASH_H
  3. #define _GHASH_H
  4.  
  5. #include <stdlib.h>
  6. #include <stdint.h>
  7. #include <string.h>
  8.  
  9.  
  10.  
  11. /* hash table entry
  12.  * embed it to your data structure
  13.  * для кучи задач этого может оказаться достаточно, но эту же структуру
  14.  * (и даже несколько, по одной для каждой хэш-таблицы)
  15.  * можно встраивать в свои данные,
  16.  * которые станут доступны из разных хэш-таблиц без дублирования
  17.  */
  18. struct gh_entry {
  19.   void *data;
  20.   void *key;
  21.   struct gh_entry *next;
  22.   uint32_t hcode,
  23.     keylen;
  24. };
  25.  
  26. /**
  27.  * hash_entry - get the user data for this entry (from include/linux/list.h)
  28.  * @ptr:    the &struct hash_entry pointer
  29.  * @type:   the type of the user data (e.g. struct my_data) embedded in this entry
  30.  * @member: the name of the gh_entry within the struct (e.g. entry)
  31.  */
  32. #define hash_entry(ptr, type, member) \
  33.     ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
  34.  
  35.  
  36. // user defined hash-function
  37. typedef uint32_t (*gh_hash)(const void *key, uint32_t keylen);
  38. // user defined keys compare function
  39. typedef int (*gh_equals)(const void *key1, uint32_t key1len,
  40.               const void *key2, uint32_t key2len);
  41. struct gh_table;
  42. // user defined callback (used for remove entry, traverse and destroy table)
  43. typedef void (*gh_ucbf)(struct gh_table *htab, struct gh_entry *entry);
  44.  
  45. // hash table control block
  46. struct gh_table {
  47.   uint32_t capacity,       // maximum number of buckets
  48.     size;                  // current number of entries
  49.   struct gh_entry **table; // array of LIFO collisions lists
  50.   gh_hash fhash;           // calculate hash for key
  51.   gh_equals equals;        // compare 2 keys, returns 1 if they are equal
  52. };
  53.  
  54. // macros for lookup/remove char *keys
  55. #define GH_FIND_STR(tab,key) ({char *_k = (char *)(key);    \
  56.       gh_lookup((tab), _k, strlen(_k));})
  57. #define GH_REMOVE_STR(tab,key) ({char *_k = (char *)(key);  \
  58.       gh_remove((tab), _k, strlen(_k));})
  59.  
  60. // default keys compare function
  61. static int _gh_key_equals (const void *key1, uint32_t key1len,
  62.                const void *key2, uint32_t key2len) {
  63.   return key1len == key2len ? memcmp(key1, key2, key1len) == 0 : 0;
  64. }
  65.  
  66. // Bernstein -- default hash function (found somewhere on the Internet)
  67. static uint32_t _gh_bernstein (const void *key, uint32_t keylen) {
  68.   uint32_t seed = 1, i;
  69.   const uint8_t * data = (const uint8_t*)key;
  70.  
  71.   for(i = 0; i < keylen; ++i)
  72.     seed = 33 * seed + data[i];
  73.  
  74.   return seed;
  75. }
  76.  
  77. static inline void *memdup (const void *src, size_t len) {
  78.   void *res = malloc(len);
  79.   if (res)
  80.     memcpy(res, src, len);
  81.   return res;
  82. }
  83.  
  84.  
  85. /**
  86.  * gh_init --  init new hashtable
  87.  * @capacity: number of backets (collision chains)
  88.  * @fhash: user hash function
  89.  * @fcmp: user keys equal compare function
  90.  * @frem: callback function, called before free() when entry removes from table
  91.  *
  92.  * Returns: 1 -- OK, 0 -- no memory
  93.  */
  94. static int
  95. gh_init (struct gh_table *htab,
  96.      uint32_t capacity, gh_hash fhash, gh_equals fcmp)
  97. {
  98.   if (capacity < 2)
  99.     capacity = 2;
  100.  
  101.   if ((htab->table = (struct gh_entry **)calloc(htab->capacity = capacity,
  102.                         sizeof(struct gh_entry *)))) {
  103.     htab->size = 0;
  104.     htab->fhash = fhash ? fhash : _gh_bernstein;
  105.     htab->equals = fcmp ? fcmp :_gh_key_equals;
  106.   }
  107.  
  108.   return htab->table != 0;
  109. }
  110.  
  111. /**
  112.  * gh_destroy --  free all memory, @htab invalidate
  113.  * @htab: hash table
  114.  * @uf: function, if not NULL, called for each removed entry
  115.  * Note: @uf called after removing gh_entry from chain
  116.  */
  117. static void
  118. gh_destroy (struct gh_table *htab, gh_ucbf uf)
  119. {
  120.   uint32_t i;
  121.  
  122.   for (i = 0; i < htab->capacity; i++)
  123.     while (htab->table[i]) {
  124.       struct gh_entry *p = htab->table[i];
  125.       htab->table[i] = p->next;
  126.       if (uf)
  127.     uf(htab, p);
  128.     }
  129.  
  130.   free(htab->table);
  131.   htab->table = 0;
  132. }
  133.  
  134.  
  135. /*
  136.   Две функции для перебора элементов таблицы.
  137.   Типичное использование
  138.     for (p = gh_first_entry(&htab); p; p = gh_next_entry(&htab, p))
  139.       ...
  140.  */
  141. /**
  142.  * gh_first_entry -- get first entry
  143.  * @htab:  hash table ptr
  144.  * Returns: ptr to gh_entry or 0 (empty table);
  145.  */
  146. static struct gh_entry *
  147. gh_first_entry (struct gh_table *htab)
  148. {
  149.   uint32_t i;
  150.   if (htab->size)
  151.     for (i = 0; i < htab->capacity; i++)
  152.       if (htab->table[i])
  153.     return htab->table[i];
  154.   return 0;
  155. }
  156.  
  157. /**
  158.  * gh_next_entry -- get next entry
  159.  * @htab:  hash table ptr
  160.  * @eprev: ptr to VALID gh_entry (returned by gh_first_entry() or similar)
  161.  * Returns: ptr to gh_entry or 0 (no more entries);
  162.  */
  163. static struct gh_entry *
  164. gh_next_entry (struct gh_table *htab, struct gh_entry *eprev)
  165. {
  166.   if (eprev) {
  167.     if (eprev->next)
  168.       return eprev->next;
  169.     uint32_t i = eprev->hcode % htab->capacity + 1;
  170.     for (; i < htab->capacity; i++)
  171.       if (htab->table[i])
  172.     return htab->table[i];
  173.   }
  174.   return 0;
  175. }
  176.  
  177. /**
  178.  * gh_next_samekey_entry -- get next entry with same key
  179.  * @htab:  hash table ptr
  180.  * @eprev: ptr to VALID gh_entry (returned by gh_first_entry() or similar)
  181.  * Returns: ptr to gh_entry or 0 (no more entries with eprev->key);
  182.  * Note: useful for fetch entries with the same key from multiset
  183.  */
  184. static struct gh_entry *
  185. gh_next_samekey_entry (struct gh_table *htab, struct gh_entry *eprev)
  186. {
  187.   // entry with the same key must be in the same backet
  188.   struct gh_entry *p = eprev ? eprev->next : 0;
  189.  
  190.   for (; p; p = p->next)
  191.     if (eprev->hcode == p->hcode &&
  192.     htab->equals(eprev->key, eprev->keylen, p->key, p->keylen))
  193.       return p;
  194.  
  195.   return 0;
  196. }
  197.  
  198. /**
  199.  * gh_insert --  insert new entry in table
  200.  * @htab:  hash table ptr
  201.  * @ep: ptr to gh_entry with filled .key and .keylen
  202.  * Returns: ptr to gh_entry (@ep)
  203.  * Notes: we do multiset, so never check is the same key in table or not
  204.  *        advise: use strlen() for string keys length,
  205.  *        but insert them with trailing nil (use strdup())
  206.  */
  207. static struct gh_entry *
  208. gh_insert (struct gh_table *htab, struct gh_entry *ep)
  209. {
  210.   if (ep) {
  211.     ep->hcode = htab->fhash(ep->key, ep->keylen);
  212.     uint32_t i = ep->hcode % htab->capacity;
  213.     ep->next = htab->table[i];
  214.     htab->table[i] = ep;
  215.     htab->size++;
  216.   }
  217.  
  218.   return ep;
  219. }
  220.  
  221. static inline struct gh_entry *gh_insert_data (struct gh_table *htab,
  222.                            struct gh_entry *ep,
  223.                            void *key,
  224.                            uint32_t keylen,
  225.                            void *data) {
  226.   if (ep) {
  227.     ep->key = key;
  228.     ep->keylen = keylen;
  229.     ep->data = data;
  230.   }
  231.   return gh_insert(htab, ep);
  232. }
  233.  
  234. static inline struct gh_entry *gh_insert_keydup_data (struct gh_table *htab,
  235.                               struct gh_entry *ep,
  236.                               void *key,
  237.                               uint32_t keylen,
  238.                               void *data) {
  239.   return (key = memdup(key, keylen)) ?
  240.     gh_insert_data(htab, ep, key, keylen, data) : 0;
  241. }
  242.  
  243. static inline struct gh_entry *gh_insert_strkeydup_data (struct gh_table *htab,
  244.                              struct gh_entry *ep,
  245.                              char *key,
  246.                              void *data) {
  247.   return (key = strdup(key)) ?
  248.     gh_insert_data(htab, ep, key, strlen(key), data) : 0;
  249. }
  250.  
  251. static inline struct gh_entry *gh_insert_strkey_data (struct gh_table *htab,
  252.                               struct gh_entry *ep,
  253.                               char *key,
  254.                               void *data) {
  255.   return gh_insert_data(htab, ep, key, strlen(key), data);
  256. }
  257.  
  258. /**
  259.  * gh_lookup --  find entry by key
  260.  * @htab:  hash table ptr
  261.  * @key: ptr to key
  262.  * @keylen: key length in bytes
  263.  * Returns: ptr to gh_entry or 0 (no such key in table)
  264.  */
  265. static struct gh_entry *
  266. gh_lookup (struct gh_table *htab, const void *key, uint32_t keylen)
  267. {
  268.   uint32_t hcode = htab->fhash(key, keylen), i = hcode % htab->capacity;
  269.   struct gh_entry *p = htab->table[i];
  270.  
  271.   while (p) {
  272.     if (p->hcode == hcode
  273.     && htab->equals(p->key, p->keylen, key, keylen))
  274.       break;
  275.     p = p->next;
  276.   }
  277.  
  278.   return p;
  279. }
  280.  
  281.  
  282.  
  283. /**
  284.  * gh_remove --  find entry by key and remove it
  285.  * @htab:  hash table ptr
  286.  * @key: ptr to key
  287.  * @keylen: key length in bytes
  288.  * Returns: ptr to gh_entry or 0 (no such key in table)
  289.  */
  290. static struct gh_entry *
  291. gh_remove (struct gh_table *htab, const void *key, uint32_t keylen)
  292. {
  293.   uint32_t hcode = htab->fhash(key, keylen), i = hcode % htab->capacity;
  294.   struct gh_entry *pp = 0, *p = htab->table[i];
  295.  
  296.   while (p) {
  297.     if (p->hcode == hcode
  298.     && htab->equals(p->key, p->keylen, key, keylen)) {
  299.       if (pp)
  300.     pp->next = p->next;
  301.       else
  302.     htab->table[i] = p->next;
  303.       htab->size--;
  304.       break;
  305.     }
  306.     pp = p;
  307.     p = p->next;
  308.   }
  309.  
  310.   return p;
  311. }
  312.  
  313. /**
  314.  * gh_remove_entry --  remove entry from table
  315.  * @htab:  hash table ptr
  316.  * @ep: ptr to VALID gh_entry (returned by gh_first_entry() or similar)
  317.  * Returns: ptr to this gh_entry or 0 (entry not found in table)
  318.  */
  319. static struct gh_entry *
  320. gh_remove_entry (struct gh_table *htab, struct gh_entry *ep)
  321. {
  322.   uint32_t i = ep->hcode % htab->capacity;
  323.   struct gh_entry *pp = 0, *p = htab->table[i];
  324.  
  325.   while (p) {
  326.     if (p == ep) {
  327.       if (pp)
  328.     pp->next = ep->next;
  329.       else
  330.     htab->table[i] = ep->next;
  331.       htab->size--;
  332.       break;
  333.     }
  334.     pp = p->next;
  335.     p = p->next;
  336.   }
  337.  
  338.   return p;
  339. }
  340. /**
  341.  * gh_rehash --  change table capacity
  342.  * @htab:  hash table ptr
  343.  * @capacity: new capacity
  344.  * Returns: 1 or 0 (no memory, table not change)
  345.  * Note: if (capacity == 0) capacity = (old_capacity * 3) / 2 + 1
  346.  */
  347. // returns 0 if no memory
  348. static int
  349. gh_rehash (struct gh_table *htab, int capacity)
  350. {
  351.   if (capacity == 0)
  352.     capacity = (htab->capacity * 3) / 2 + 1;
  353.   struct gh_entry **t = (typeof(t))calloc(capacity, sizeof(*t));
  354.   if (!t)
  355.     return 0;
  356.  
  357.   uint32_t i, j;
  358.  
  359.   for (i = 0; i < htab->capacity; i++)
  360.     while (htab->table[i]) {
  361.       struct gh_entry *p = htab->table[i];
  362.       htab->table[i] = p->next;
  363.       j = p->hcode % capacity;
  364.       p->next = t[j];
  365.       t[j] = p;
  366.     }
  367.  
  368.   free(htab->table);
  369.   htab->table = t;
  370.   htab->capacity = capacity;
  371.   return 1;
  372. }
  373.  
  374.  
  375. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement