LCOV - code coverage report
Current view: top level - src/plugins/ni/nickel-1.1.0/src/include/bohr - ds_hash.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 50 76 65.8 %
Date: 2019-09-12 12:28:41 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Darmstadtium - a library of data structures
       3             :  * Ds_hash - a hash table library
       4             :  * One of the Bohr Game Libraries (see chaoslizard.org/devel/bohr)
       5             :  * Copyright (C) 2008 Charles Lindsay.  Some rights reserved; see COPYING.
       6             :  * $Id: ds_hash.h 317 2008-01-05 21:45:34Z chaz $
       7             :  ******************************************************************************/
       8             : 
       9             : 
      10             : #ifndef __bohr_ds_hash_h__
      11             : #define __bohr_ds_hash_h__
      12             : 
      13             : #ifndef __STDC_CONSTANT_MACROS
      14             : #define __STDC_CONSTANT_MACROS
      15             : #endif
      16             : #ifndef __STDC_FORMAT_MACROS
      17             : #define __STDC_FORMAT_MACROS
      18             : #endif
      19             : 
      20             : #include <inttypes.h>
      21             : #include <stddef.h>
      22             : #include <stdint.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : 
      26             : 
      27             : // Controls inlining of this library's functions.
      28             : #ifndef Ds_HASH_INLINE
      29             : #ifdef Ds_INLINE
      30             : #define Ds_HASH_INLINE Ds_INLINE
      31             : #else
      32             : #define Ds_HASH_INLINE inline static
      33             : #endif
      34             : #endif
      35             : 
      36             : // Nix non-critical C99 keywords in compilers that don't support them.
      37             : #if ((!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(restrict))
      38             : #define restrict
      39             : #define _Ds_HASH_DEFINED_RESTRICT
      40             : #endif
      41             : 
      42             : 
      43             : // A type to hold a hash value.  We also define the standard constant-
      44             : // declaration macro, max value, and printf/scanf specifiers.
      45             : #ifndef Ds_HASH_T_DEFINED
      46             : #define Ds_HASH_T_DEFINED
      47             : typedef uint32_t Ds_hash_t;
      48             : #define Ds_HASH_C UINT32_C
      49             : #define Ds_HASH_MAX UINT32_MAX
      50             : #define PRIdDs_HASH PRId32
      51             : #define PRIiDs_HASH PRIi32
      52             : #define PRIoDs_HASH PRIo32
      53             : #define PRIuDs_HASH PRIu32
      54             : #define PRIxDs_HASH PRIx32
      55             : #define PRIXDs_HASH PRIX32
      56             : #define SCNdDs_HASH SCNd32
      57             : #define SCNiDs_HASH SCNi32
      58             : #define SCNoDs_HASH SCNo32
      59             : #define SCNuDs_HASH SCNu32
      60             : #define SCNxDs_HASH SCNx32
      61             : #endif
      62             : 
      63             : 
      64             : // A chainable entry in a Ds_hash_table.
      65             : typedef struct Ds_hash_entry
      66             : {
      67             :         struct Ds_hash_entry * next; // linked list next pointer
      68             : 
      69             :         Ds_hash_t hash; // the item's hash value
      70             :         size_t bucket;  // which bucket it's in
      71             :         size_t size;    // how big the item is
      72             :         uint8_t item[]; // the item itself (struct hack, valid C99)
      73             : 
      74             : } Ds_hash_entry;
      75             : 
      76             : 
      77             : // Define a vector that works with our Ds_hash_entries.
      78             : #define Ds_VECTOR_BEHAVIOR 2
      79             : #define Ds_VECTOR_TYPE Ds_hash_entry *
      80             : #define Ds_VECTOR_SUFFIX _Dsh
      81             : #include <bohr/ds_vector.h>
      82             : 
      83             : 
      84             : // A hash table (an alias for a specific kind of Ds_vector).
      85             : typedef Ds_vector_Dsh Ds_hash_table;
      86             : #define Ds_HASH_TABLE_INIT Ds_VECTOR_INIT // initializer
      87             : 
      88             : 
      89             : // Function to compare two hash items; return similar to strcmp--declare as:
      90             : //   int MyCompare(const void * restrict key, size_t key_size,
      91             : //                 const void * restrict item, size_t item_size);
      92             : typedef int (*Ds_hash_compare_fn) (const void * key, size_t key_size, const void * item, size_t item_size);
      93             : 
      94             : 
      95             : /* Reserves initial space in the Ds_hash_table.  size must be a power of 2.
      96             :  */
      97        2090 : Ds_HASH_INLINE int Ds_InitHashTable (Ds_hash_table * restrict table, size_t size)
      98             : {
      99        2090 :         if (!Ds_InitVector_Dsh ((Ds_vector_Dsh *) table, size)) return 0;
     100             : 
     101        2090 :         memset (table->buf, 0, size * sizeof (Ds_hash_entry *));
     102        2090 :         return 1;
     103             : }
     104             : 
     105             : /* Frees memory associated with the Ds_hash_table.
     106             :  */
     107        2090 : Ds_HASH_INLINE void Ds_FreeHashTable (Ds_hash_table * restrict table)
     108             : {
     109       69098 :         for (size_t i = 0; i < table->cap; ++i)
     110             :         {
     111             :                 Ds_hash_entry * head;
     112             : 
     113       67008 :                 head = table->buf[i];
     114      135920 :                 while (head)
     115             :                 {
     116             :                         Ds_hash_entry * t;
     117             : 
     118        1904 :                         t = head;
     119        1904 :                         head = head->next;
     120        1904 :                         elektraFree (t);
     121             :                 }
     122             :         }
     123             : 
     124        2090 :         Ds_FreeVector_Dsh ((Ds_vector_Dsh *) table);
     125        2090 : }
     126             : 
     127             : /* Iterates over all the entries in the Ds_hash_table.  Specify NULL for prev to
     128             :  * return the first Ds_hash_entry.  Subsequently pass the previous return value.
     129             :  * Returns NULL when there are no remaining entries.
     130             :  */
     131             : Ds_HASH_INLINE Ds_hash_entry * Ds_NextHashEntry (const Ds_hash_table * restrict table, const Ds_hash_entry * restrict prev)
     132             : {
     133        7333 :         Ds_hash_entry * n = NULL;
     134        7333 :         size_t bucket = 0;
     135             : 
     136        7333 :         if (prev)
     137             :         {
     138        4277 :                 n = prev->next;
     139        4277 :                 bucket = prev->bucket + 1;
     140             :         }
     141             : 
     142      105381 :         while (!n && bucket < table->cap)
     143       98048 :                 n = table->buf[bucket++];
     144             : 
     145             :         return n;
     146             : }
     147             : 
     148             : /* Inserts an item into the Ds_hash_table.  The item has the given hash value
     149             :  * and size.  Returns the new Ds_hash_entry or NULL if it fails.
     150             :  */
     151        1904 : Ds_HASH_INLINE Ds_hash_entry * Ds_InsertHashItem (Ds_hash_table * restrict table, const void * restrict item, size_t size, Ds_hash_t hash)
     152             : {
     153             :         Ds_hash_entry * n;
     154             : 
     155        1904 :         if ((n = (Ds_hash_entry *) malloc (sizeof (Ds_hash_entry) + size)) != NULL)
     156             :         {
     157        1904 :                 n->hash = hash;
     158        1904 :                 n->bucket = hash & (table->cap - 1);
     159        1904 :                 n->size = size;
     160        1904 :                 memcpy (n->item, item, size);
     161             : 
     162        1904 :                 n->next = table->buf[n->bucket];
     163        1904 :                 table->buf[n->bucket] = n;
     164        1904 :                 table->num++;
     165             :         }
     166             : 
     167        1904 :         return n;
     168             : }
     169             : 
     170             : /* Removes a Ds_hash_entry from the Ds_hash_table.  The entry must belong to the
     171             :  * table.  Returns 0/nonzero on failure/success.
     172             :  */
     173           0 : Ds_HASH_INLINE int Ds_RemoveHashEntry (Ds_hash_table * restrict table, Ds_hash_entry * restrict entry)
     174             : {
     175           0 :         int found = 0;
     176             :         Ds_hash_entry * t;
     177             : 
     178           0 :         if (entry == (t = table->buf[entry->bucket]))
     179             :         {
     180           0 :                 table->buf[entry->bucket] = entry->next;
     181           0 :                 found = 1;
     182             :         }
     183           0 :         else if (t)
     184             :         {
     185           0 :                 while (t->next)
     186             :                 {
     187           0 :                         if (entry == t->next)
     188             :                         {
     189           0 :                                 t->next = entry->next;
     190           0 :                                 found = 1;
     191             :                                 break;
     192             :                         }
     193             :                 }
     194             :         }
     195             : 
     196           0 :         if (found)
     197             :         {
     198           0 :                 elektraFree (entry);
     199           0 :                 table->num--;
     200             :         }
     201             : 
     202           0 :         return found;
     203             : }
     204             : 
     205             : /* Searches the Ds_hash_table for a given key item that has the given hash
     206             :  * value.  Returns the first entry matching the hash value, or if you specify a
     207             :  * compare function, returns the first entry the compare function returns 0 on.
     208             :  * Returns NULL if it's not found.  key and size are only used to pass to
     209             :  * compare().
     210             :  */
     211             : Ds_HASH_INLINE Ds_hash_entry * Ds_SearchHashTable (const Ds_hash_table * restrict table, const void * restrict key, size_t size,
     212             :                                                    Ds_hash_t hash, Ds_hash_compare_fn compare)
     213             : {
     214             :         Ds_hash_entry * t;
     215             : 
     216        2357 :         t = table->buf[hash & (table->cap - 1)];
     217        2584 :         while (t && hash != t->hash && (!compare || compare (key, size, &t->item, t->size)))
     218             :         {
     219         227 :                 t = t->next;
     220             :         }
     221             : 
     222             :         return t;
     223             : }
     224             : 
     225             : /* Resizes the Ds_hash_table, moving entries around.  size must be a power of 2.
     226             :  */
     227           4 : Ds_HASH_INLINE int Ds_ResizeHashTable (Ds_hash_table * restrict table, size_t size)
     228             : {
     229           4 :         if (size > table->cap)
     230             :         {
     231             :                 size_t old_size;
     232             : 
     233           4 :                 old_size = table->cap;
     234           4 :                 if (!Ds_ResizeVector_Dsh ((Ds_vector_Dsh *) table, size)) return 0;
     235           4 :                 memset (table->buf + old_size, 0, (size - old_size) * sizeof (Ds_hash_entry *));
     236             : 
     237         132 :                 for (size_t i = 0; i < old_size; ++i)
     238             :                 {
     239             :                         size_t bucket;
     240             :                         Ds_hash_entry *e, *t;
     241             : 
     242         128 :                         e = table->buf[i];
     243         278 :                         while (e && (bucket = e->hash & (size - 1)) != i)
     244             :                         {
     245          22 :                                 t = e->next;
     246          22 :                                 e->next = table->buf[e->bucket = bucket];
     247          22 :                                 table->buf[bucket] = e;
     248          22 :                                 table->buf[i] = e = t;
     249             :                         }
     250         146 :                         while (e && (t = e->next) != NULL)
     251             :                         {
     252          18 :                                 if ((bucket = t->hash & (size - 1)) != i)
     253             :                                 {
     254           4 :                                         e->next = t->next;
     255           4 :                                         t->next = table->buf[t->bucket = bucket];
     256           4 :                                         table->buf[bucket] = t;
     257             :                                 }
     258             :                                 else
     259             :                                         e = t;
     260             :                         }
     261             :                 }
     262             :         }
     263           0 :         else if (size < table->cap)
     264             :         {
     265             :                 size_t old_num;
     266             : 
     267           0 :                 for (size_t i = size; i < table->cap; ++i)
     268             :                 {
     269             :                         Ds_hash_entry * t;
     270             : 
     271           0 :                         if ((t = table->buf[i]) != NULL)
     272             :                         {
     273             :                                 size_t bucket;
     274             : 
     275           0 :                                 bucket = i & (size - 1);
     276           0 :                                 while (t->next)
     277             :                                 {
     278           0 :                                         t->bucket = bucket;
     279           0 :                                         t = t->next;
     280             :                                 }
     281           0 :                                 t->next = table->buf[t->bucket = bucket];
     282           0 :                                 table->buf[bucket] = table->buf[i];
     283             :                         }
     284             :                 }
     285             : 
     286           0 :                 old_num = table->num;
     287           0 :                 if (!Ds_ResizeVector_Dsh ((Ds_vector_Dsh *) table, size)) return 0;
     288           0 :                 table->num = old_num;
     289             :         }
     290             : 
     291             :         return 1;
     292             : }
     293             : 
     294             : 
     295             : #ifdef _Ds_HASH_DEFINED_RESTRICT
     296             : #undef _Ds_HASH_DEFINED_RESTRICT
     297             : #undef restrict
     298             : #endif
     299             : 
     300             : #endif

Generated by: LCOV version 1.13