librnr  1.14.5
RoadNarrows Robotics Common Library 1
hash.c File Reference

General purpose hash data and function declarations. More...

#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "rnr/rnrconfig.h"
#include "rnr/new.h"
#include "rnr/log.h"
#include "rnr/hash.h"

Go to the source code of this file.

Functions

static void compute_bits ()
 Compute the number of bits in the hash_val_t type. More...
 
static bool_t is_power_of_two (hash_val_t arg)
 Verify whether the given argument is a power of two. More...
 
static hash_val_t compute_mask (hashcount_t size)
 Compute a mask for a given table size. More...
 
static void init_hash_sizes (hash_t *hash, hashcount_t minsize, hashcount_t maxsize)
 Initialize the table size values. More...
 
static hash_val_t hash_fun_default (const void *key)
 Default hashing function over null-terminated string keys. More...
 
static int hash_comp_default (const void *key1, const void *key2)
 Default hash key comparator function of null-terminated key strings. More...
 
static void clear_table (hash_t *hash)
 Initialize the table of pointers to null. More...
 
static void grow_table (hash_t *hash)
 Double the size of a dynamic table. More...
 
static void shrink_table (hash_t *hash)
 Cut a dynamic table size in half. More...
 
hash_thash_table_create (bool_t isdynamic, hashcount_t minsize, hashcount_t maxsize, hash_comp_t compfun, hash_fun_t hashfun, hnode_data_free_t freedatafun)
 Create a dynamic hash table. More...
 
void hash_table_destroy (hash_t *hash)
 Delete the hash table, all of its entries, and all of the user data. More...
 
void hash_table_delete (hash_t *hash)
 Frees a dynamic hash table structure. More...
 
hash_thash_table_init (hash_t *hash, hashcount_t minsize, hashcount_t maxsize, hash_comp_t compfun, hash_fun_t hashfun, hnode_data_free_t freedatafun, hnode_t **table, hashcount_t nchains)
 Initialize a user supplied hash table. More...
 
bool_t hash_table_verify (hash_t *hash)
 Verify hash table consistency. More...
 
void hash_scan_begin (hscan_t *scan, hash_t *hash)
 Reset the hash scanner (iterator). More...
 
hnode_thash_scan_next (hscan_t *scan)
 Retrieve the next node from the hash table. More...
 
void hash_node_insert (hash_t *hash, hnode_t *node, void *key)
 Insert a node into the hash table. More...
 
hnode_thash_node_unlink (hash_t *hash, hnode_t *node)
 Unlink the given node from the hash table. More...
 
hnode_thash_node_fast_unlink (hash_t *hash, hnode_t *node)
 Fast version to unlink the given node from the hash table. More...
 
void hash_node_delete (hash_t *hash, hnode_t *node)
 Unlink and delete a hash node from the hash table. More...
 
hnode_thash_lookup (hash_t *hash, const void *key)
 Find a node in the hash table and return a pointer to it. More...
 
bool_t hash_insert (hash_t *hash, void *key, void *data)
 Insert user data with the given key into the hash table. More...
 
bool_t hash_delete (hash_t *hash, void *key)
 Unlink and delete a hash node with the given key from the hash table. More...
 
void hash_set_self_verify (bool_t selfverify)
 Enable (disable) automatic self-checks during hash table modification operatations. More...
 
hnode_thnode_create (void *data)
 Create a hash table node dynamically and assign it the given data. More...
 
hnode_thnode_init (hnode_t *node, void *data)
 Initialize a client-supplied hash node. More...
 
void hnode_destroy (hnode_t *node, hnode_data_free_t freedatafun)
 Hash node and user data deallocator. More...
 
void hnode_delete (hnode_t *node)
 Destroy a dynamically allocated node. More...
 

Variables

static int hash_val_t_bit = 0
 Number of bits in hashed value. Must be a power of 2.
 
static bool_t hash_self_verify = false
 Do [not] perform auto-verification after hash table operations.
 

Detailed Description

General purpose hash data and function declarations.

LastChangedDate
2010-03-24 10:19:36 -0600 (Wed, 24 Mar 2010)
Rev
307

This file has been modified from the original source (see below).

Exceptons map to assert() calls that terminate the calling application.

Todo:
Convert the assert() error handling to appropriate return codes and librnr error handling.
Author
Robin Knight (robin.nosp@m..kni.nosp@m.ght@r.nosp@m.oadn.nosp@m.arrow.nosp@m.s.co.nosp@m.m)

Original Source and Copyright:
Original Author:
Kaz Kylheku (kaz@a.nosp@m.shi..nosp@m.footp.nosp@m.rint.nosp@m.s.net)
Original Copyright:
(C) 1997
Original Header:
See "Original Source Header EULA" in source file.

Definition in file hash.c.

Function Documentation

static void clear_table ( hash_t hash)
static

Initialize the table of pointers to null.

Parameters
hashHash table.

Definition at line 307 of file hash.c.

References hash_t::nchains, NULL, and hash_t::table.

Referenced by hash_table_create(), and hash_table_init().

308 {
309  hash_val_t i;
310 
311  for(i=0; i<hash->nchains; i++)
312  {
313  hash->table[i] = NULL;
314  }
315 }
hashcount_t nchains
Note 6.
Definition: hash.h:275
#define NULL
null pointer
Definition: rnrconfig.h:199
hnode_t ** table
Note 1.
Definition: hash.h:270
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
static void compute_bits ( )
static

Compute the number of bits in the hash_val_t type.

We know that hash_val_t is an unsigned integral type. Thus the highest value it can hold is a Mersenne number (power of two, less one). We initialize a hash_val_t object with this value and then shift bits out one by one while counting.

Notes & Steps:
1. HASH_VAL_T_MAX is a Mersenne number—one that is one less than a power of two. This means that its binary representation consists of all one bits, and hence ``val'' is initialized to all one bits.
2. We reset the bit count to zero in case this function is invoked more than once.
3. While bits remain in val, we increment the bit count and shift it to the right, replacing the topmost bit by zero.

Definition at line 141 of file hash.c.

References hash_val_t_bit, and HASH_VAL_T_MAX.

Referenced by hash_table_create(), and hash_table_init().

142 {
143  hash_val_t val = HASH_VAL_T_MAX; // Steps 1
144  int bits = 0;
145 
146  // Steps 3
147  while(val)
148  {
149  bits++;
150  val >>= 1;
151  }
152 
153  hash_val_t_bit = bits;
154 }
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
#define HASH_VAL_T_MAX
Maximum hashed value (a Mersenne number 2^N-1)
Definition: hash.h:86
static hash_val_t compute_mask ( hashcount_t  size)
static

Compute a mask for a given table size.

Parameters
sizeTable size.
Returns
Shift amount.

Definition at line 185 of file hash.c.

References is_power_of_two().

Referenced by hash_table_create(), and hash_table_init().

186 {
187  hash_val_t mask = size;
188 
189  assert(is_power_of_two(size));
190  assert(size >= 2);
191 
192  mask /= 2;
193 
194  while( (mask & 0x01) == 0 )
195  {
196  mask |= (mask >> 1);
197  }
198 
199  return mask;
200 }
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
static bool_t is_power_of_two(hash_val_t arg)
Verify whether the given argument is a power of two.
Definition: hash.c:163
static void grow_table ( hash_t hash)
static

Double the size of a dynamic table.

This works as follows:

Each chain splits into two adjacent chains. The shift amount increases by one, exposing an additional bit of each hashed key. For each node in the original chain, the value of this newly exposed bit will decide which of the two new chains will receive the node: if the bit is 1, the chain with the higher index will have the node, otherwise the lower chain will receive the node. In this manner, the hash table will continue to function exactly as before without having to rehash any of the keys.

Notes & Steps:
1. Overflow check.
2. The new number of chains is twice the old number of chains.
3. The new mask is one bit wider than the previous, revealing a new bit in all hashed keys.
4. Allocate a new table of chain pointers that is twice as large as the previous one.
5. If the reallocation was successful, we perform the rest of the growth algorithm, otherwise we do nothing.
6. The exposed_bit variable holds a mask with which each hashed key can be AND-ed to test the value of its newly exposed bit.
7. Loop over the lower half of the table, which, at first, holds all of the chains.
8. Each chain from the original table must be split into two chains. The nodes of each chain are examined in turn. The ones whose key value's newly exposed bit is 1 are removed from the chain and put into newchain (Steps 9 through 14). After this separation, the new chain is assigned into its appropriate place in the upper half of the table (Step 15).
9. Since we have relocated the table of pointers, we have to fix the back-reference from the first node of each non-empty chain so it properly refers to the moved pointer.
10. We loop over the even chain looking for any nodes whose exposed bit is set. Such nodes are removed from the lower-half chain and put into its upper-half sister.
11. Before moving the node to the other chain, we remember what the next node is so we can coninue the loop. We have to do this because we will be overwriting the node's next pointer when we insert it to its new home.
12. The next node's back pointer must be updated to skip to the previous node.
13. The deleted node's back pointer must be updated to refer to the next node.
14. We insert the node at the beginning of the new chain.
15. Place the new chain into an upper-half slot.
16. We have finished dealing with the chains and nodes. We now update the various bookeeping fields of the hash structure.
Parameters
hashHash table.
Exceptions
Table OverflowReached system limits.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 388 of file hash.c.

References _TPTR, _VARFMT, hash_self_verify, hash_table_verify(), hash_t::highmark, hnode_t::hkey, LOGDIAG4, LOGDIAG4CALL, hash_t::lowmark, hash_t::mask, hash_t::nchains, new_overs(), hnode_t::next, NULL, hnode_t::pself, and hash_t::table.

Referenced by hash_node_insert().

389 {
390  hnode_t **newtable;
391  size_t size;
392 
393  LOGDIAG4CALL(_TPTR(hash));
394 
395  // Step 1
396  assert(2 * hash->nchains > hash->nchains);
397 
398  // Step 4
399  size = sizeof(hnode_t *) * hash->nchains;
400  newtable = new_overs(hash->table, size, size *2);
401 
402  // Step 5
403  if( newtable )
404  {
405  // Step 3
406  hash_val_t mask = (hash->mask << 1) | 1;
407 
408  // Step 6
409  hash_val_t exposed_bit = mask ^ hash->mask;
410 
411  hash_val_t chain;
412 
413  assert(mask != hash->mask);
414 
415  // Step 7
416  for(chain = 0; chain < hash->nchains; chain++)
417  {
418  // Step 8
419  hnode_t *hptr = newtable[chain];
420  hnode_t *newchain = NULL;
421 
422  // Step 9
423  if(hptr)
424  {
425  hptr->pself = &newtable[chain];
426  }
427 
428  // Step 10
429  while(hptr)
430  {
431  if((hptr->hkey & exposed_bit))
432  {
433  // Step 11
434  hnode_t *next = hptr->next;
435 
436  // Step 12
437  if(next)
438  {
439  next->pself = hptr->pself;
440  }
441 
442  // Step 13
443  *hptr->pself = next;
444 
445  // Step 14
446  hptr->next = newchain;
447  if(newchain)
448  {
449  newchain->pself = &hptr->next;
450  }
451  newchain = hptr;
452  hptr->pself = &newchain;
453  hptr = next;
454  }
455  else
456  {
457  hptr = hptr->next;
458  }
459  }
460  // Step 15
461  newtable[chain + hash->nchains] = newchain;
462  if(newchain)
463  {
464  newchain->pself = &newtable[chain + hash->nchains];
465  }
466  }
467 
468  // Step 16
469  hash->table = newtable;
470  hash->mask = mask;
471  hash->nchains *= 2;
472  hash->lowmark *= 2;
473  hash->highmark *= 2;
474  }
475 
476  LOGDIAG4(_VARFMT(hash->nchains, "%lu") ", " _VARFMT(hash->lowmark, "%lu") ", "
477  _VARFMT(hash->highmark, "%lu") ", " _VARFMT(hash->mask, "0x%lx"),
478  hash->nchains, hash->lowmark, hash->highmark, hash->mask);
479 
480  if( hash_self_verify )
481  {
482  assert(hash_table_verify(hash));
483  }
484 }
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t nchains
Note 6.
Definition: hash.h:275
#define NULL
null pointer
Definition: rnrconfig.h:199
struct hnode_t * next
<Note 1
Definition: hash.h:152
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
#define LOGDIAG4(fmt,...)
Standard Diagnostic Level 4 logging.
Definition: log.h:386
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
#define _VARFMT(var, fmt)
log Variable Format.
Definition: log.h:555
void * new_overs(void *pSrc, size_t sizeDup, size_t sizeNew)
Allocate and duplicate.
Definition: new.c:112
hashcount_t lowmark
Note 5.
Definition: hash.h:274
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
Hash chain node structure.
Definition: hash.h:149
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
hash_val_t hkey
Note 6.
Definition: hash.h:156
static int hash_comp_default ( const void *  key1,
const void *  key2 
)
static

Default hash key comparator function of null-terminated key strings.

Parameters
key1Key string 1.
key2Key string 2.
Returns
Returns <0, 0, >0 if key1 is lexigraphically less than key2, respectively.

Definition at line 297 of file hash.c.

Referenced by hash_table_create(), and hash_table_init().

298 {
299  return strcmp((const char *)key1, (const char *)key2);
300 }
bool_t hash_delete ( hash_t hash,
void *  key 
)

Unlink and delete a hash node with the given key from the hash table.

The user data and key are deallocated as per the any user supplied data free function. The node is then deallocated.

Parameters
hashHash table.
keyHash key.
Returns
Returns true if successful, else returns false.
Exceptions
Not InitialzedHashing not initialized.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1310 of file hash.c.

References hash_t::freenodedata, hash_lookup(), hash_node_unlink(), hnode_destroy(), and NULL.

Referenced by ConfigDelete(), and ConfigSectionDelete().

1311 {
1312  hnode_t *node;
1313 
1314  if( (node = hash_lookup(hash, key)) != NULL )
1315  {
1316  hash_node_unlink(hash, node);
1317  hnode_destroy(node, hash->freenodedata);
1318  return true;
1319  }
1320  return false;
1321 }
#define NULL
null pointer
Definition: rnrconfig.h:199
hnode_t * hash_lookup(hash_t *hash, const void *key)
Find a node in the hash table and return a pointer to it.
Definition: hash.c:1246
hnode_t * hash_node_unlink(hash_t *hash, hnode_t *node)
Unlink the given node from the hash table.
Definition: hash.c:1128
hnode_data_free_t freenodedata
Note 11.
Definition: hash.h:280
Hash chain node structure.
Definition: hash.h:149
void hnode_destroy(hnode_t *node, hnode_data_free_t freedatafun)
Hash node and user data deallocator.
Definition: hash.c:1376
static hash_val_t hash_fun_default ( const void *  key)
static

Default hashing function over null-terminated string keys.

Parameters
keyNull-terminated key string.
Returns
Hashed value.

Definition at line 263 of file hash.c.

Referenced by hash_table_create(), and hash_table_init().

264 {
265  static unsigned long randbox[] =
266  {
267  0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
268  0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
269  0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
270  0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
271  };
272 
273  const unsigned char *str = (const unsigned char *)key;
274  hash_val_t acc = 0;
275 
276  while( *str )
277  {
278  acc ^= randbox[(*str + acc) & 0xf];
279  acc = (acc << 1) | (acc >> 31);
280  acc &= 0xffffffffU;
281  acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
282  acc = (acc << 2) | (acc >> 30);
283  acc &= 0xffffffffU;
284  }
285  return acc;
286 }
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
bool_t hash_insert ( hash_t hash,
void *  key,
void *  data 
)

Insert user data with the given key into the hash table.

The data and key are attached to new hash node which is automatically allocated and the node is inserted into the hash table.

Parameters
hashHash table.
keyHash key.
dataUser data.
Returns
Returns true if successful, else returns false.
Exceptions
Not InitialzedHashing not initialized.
Too BigReached maximum table size.
Duplicate KeyNode with key already exists.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1283 of file hash.c.

References hash_node_insert(), and hnode_create().

Referenced by ConfigSectionAddPair(), ConfigSectionNew(), force_grow(), main(), and test_hash().

1284 {
1285  hnode_t *node = hnode_create(data);
1286 
1287  if (node)
1288  {
1289  hash_node_insert(hash, node, key);
1290  return true;
1291  }
1292 
1293  return false;
1294 }
void hash_node_insert(hash_t *hash, hnode_t *node, void *key)
Insert a node into the hash table.
Definition: hash.c:1063
hnode_t * hnode_create(void *data)
Create a hash table node dynamically and assign it the given data.
Definition: hash.c:1343
Hash chain node structure.
Definition: hash.h:149
hnode_t* hash_lookup ( hash_t hash,
const void *  key 
)

Find a node in the hash table and return a pointer to it.

Notes & Steps:
1. We hash the key and keep the entire hash value. As an optimization, when we descend down the chain, we can compare hash values first and only if hash values match do we perform a full key comparison.
2. To locate the chain from among 2^N chains, we look at the lower N bits of the hash value by anding them with the current mask.
3. Looping through the chain, we compare the stored hash value inside each node against our computed hash. If they match, then we do a full comparison between the unhashed keys. If these match, we have located the entry.
Parameters
hashHash table.
keyHash key.
Returns
Returns node with key on success, NULL if node not found.

Definition at line 1246 of file hash.c.

References hash_t::compare, hash_t::hash, hnode_t::hkey, hnode_t::key, hash_t::mask, hnode_t::next, NULL, and hash_t::table.

Referenced by ConfigGetStr(), ConfigSectionAddPair(), ConfigSectionDelete(), ConfigSectionGet(), ConfigSectionNew(), hash_delete(), hash_node_fast_unlink(), hash_node_insert(), hash_node_unlink(), and main().

1247 {
1248  hash_val_t hkey, chain;
1249  hnode_t *nptr;
1250 
1251  hkey = hash->hash(key); // Step 1
1252  chain = hkey & hash->mask; // Step 2
1253 
1254  // Step 3
1255  for(nptr = hash->table[chain]; nptr; nptr = nptr->next)
1256  {
1257  if(nptr->hkey == hkey && hash->compare(nptr->key, key) == 0)
1258  {
1259  return nptr;
1260  }
1261  }
1262 
1263  return NULL;
1264 }
hash_val_t mask
Note 7.
Definition: hash.h:276
#define NULL
null pointer
Definition: rnrconfig.h:199
hash_comp_t compare
Note 9.
Definition: hash.h:278
struct hnode_t * next
<Note 1
Definition: hash.h:152
hnode_t ** table
Note 1.
Definition: hash.h:270
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
void * key
Note 4.
Definition: hash.h:154
hash_fun_t hash
Note 10.
Definition: hash.h:279
Hash chain node structure.
Definition: hash.h:149
hash_val_t hkey
Note 6.
Definition: hash.h:156
void hash_node_delete ( hash_t hash,
hnode_t node 
)

Unlink and delete a hash node from the hash table.

The user data and key are deallocated as per the any user supplied data free function. The node is then deallocated.

Parameters
hashHash table.
nodeHash node to delete.
Exceptions
Not InitialzedHashing not initialized.
No KeyHash key not found.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1217 of file hash.c.

References hash_t::freenodedata, hash_node_unlink(), and hnode_destroy().

Referenced by force_shrink(), and main().

1218 {
1219  hash_node_unlink(hash, node);
1220  hnode_destroy(node, hash->freenodedata);
1221 }
hnode_t * hash_node_unlink(hash_t *hash, hnode_t *node)
Unlink the given node from the hash table.
Definition: hash.c:1128
hnode_data_free_t freenodedata
Note 11.
Definition: hash.h:280
void hnode_destroy(hnode_t *node, hnode_data_free_t freedatafun)
Hash node and user data deallocator.
Definition: hash.c:1376
hnode_t* hash_node_fast_unlink ( hash_t hash,
hnode_t node 
)

Fast version to unlink the given node from the hash table.

Same as hash_node_unlink() except does not trigger table shrinkage. This call is optimized for hash table scan operations.

See also
hash_node_unlink().
Parameters
hashHash table.
nodeNode to unlink, typically found by scanning.
Returns
Unlinked node.
Exceptions
Not InitialzedHashing not initialized.
No KeyHash key not found.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1178 of file hash.c.

References _TPTR, hash_t::count, hash_lookup(), hash_self_verify, hash_table_verify(), hash_val_t_bit, hnode_t::key, LOGDIAG4CALL, hnode_t::next, and hnode_t::pself.

Referenced by hash_table_destroy().

1179 {
1180  LOGDIAG4CALL(_TPTR(hash), _TPTR(node));
1181 
1182  assert(hash_val_t_bit != 0);
1183  assert(hash_lookup(hash, node->key) == node); /* 1 */
1184 
1185  // Step 2 as in hash_node_inlink()
1186  if (node->next)
1187  {
1188  node->next->pself = node->pself;
1189  }
1190 
1191  // Step 3 as in hash_node_inlink()
1192  *node->pself = node->next;
1193 
1194  hash->count--;
1195 
1196  if( hash_self_verify )
1197  {
1198  assert(hash_table_verify(hash));
1199  }
1200 
1201  return node;
1202 }
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
hnode_t * hash_lookup(hash_t *hash, const void *key)
Find a node in the hash table and return a pointer to it.
Definition: hash.c:1246
struct hnode_t * next
<Note 1
Definition: hash.h:152
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hashcount_t count
Note 8.
Definition: hash.h:277
void * key
Note 4.
Definition: hash.h:154
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
void hash_node_insert ( hash_t hash,
hnode_t node,
void *  key 
)

Insert a node into the hash table.

Steps & Notes:
1. It's illegal to insert more than the maximum number of nodes. The client should verify that the hash table is not full before attempting an insertion.
2. The same key may not be inserted into a table twice.
3. If the table is dynamic and the load factor is already at >= 2, grow the table.
4. We take the top N bits of the hash value to derive the chain index, where N is the base 2 logarithm of the size of the hash table.
Parameters
hashHash table.
nodeNode to insert.
keyHash key.
Exceptions
Not InitialzedHashing not initialized.
Too BigReached maximum table size.
Duplicate KeyNode with key already exists.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1063 of file hash.c.

References _TPTR, hash_t::count, hash_t::dynamic, grow_table(), hash_t::hash, hash_lookup(), hash_self_verify, hash_table_verify(), hash_val_t_bit, hash_t::highmark, hnode_t::hkey, hnode_t::key, LOGDIAG4CALL, hash_t::mask, hash_t::maxsize, hnode_t::next, NULL, hnode_t::pself, and hash_t::table.

Referenced by hash_insert().

1064 {
1065  LOGDIAG4CALL(_TPTR(hash), _TPTR(node), _TPTR(key));
1066 
1067  hash_val_t hkey, chain;
1068 
1069  assert(hash_val_t_bit != 0);
1070  assert(hash->count < hash->maxsize); // Step 1
1071  assert(hash_lookup(hash, key) == NULL); // Step 2
1072 
1073  // Step 3
1074  if(hash->dynamic && (hash->count+1) >= hash->highmark)
1075  {
1076  grow_table(hash);
1077  }
1078 
1079  hkey = hash->hash(key);
1080  chain = hkey & hash->mask; // Step 4
1081 
1082  node->key = key;
1083  node->hkey = hkey;
1084  node->pself = hash->table + chain;
1085  node->next = hash->table[chain];
1086  if (node->next)
1087  {
1088  node->next->pself = &node->next;
1089  }
1090  hash->table[chain] = node;
1091  hash->count++;
1092 
1093  if( hash_self_verify )
1094  {
1095  assert(hash_table_verify(hash));
1096  }
1097 }
bool_t dynamic
Note 12.
Definition: hash.h:281
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t maxsize
Note 3.
Definition: hash.h:272
#define NULL
null pointer
Definition: rnrconfig.h:199
hnode_t * hash_lookup(hash_t *hash, const void *key)
Find a node in the hash table and return a pointer to it.
Definition: hash.c:1246
static void grow_table(hash_t *hash)
Double the size of a dynamic table.
Definition: hash.c:388
struct hnode_t * next
<Note 1
Definition: hash.h:152
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hashcount_t count
Note 8.
Definition: hash.h:277
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
void * key
Note 4.
Definition: hash.h:154
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
hash_fun_t hash
Note 10.
Definition: hash.h:279
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
hash_val_t hkey
Note 6.
Definition: hash.h:156
hnode_t* hash_node_unlink ( hash_t hash,
hnode_t node 
)

Unlink the given node from the hash table.

This is easy, because each node contains a back pointer to the previous node's next pointer.

No data are deleted.

Notes & Steps:
1. The node must belong to this hash table, and its key must not have been tampered with.
2. If there is a next node, then we must update its back pointer to skip this node.
3. We must update the pointer that is pointed at by the back-pointer to skip over the node that is being deleted and instead point to the successor (or to NULL if the node being deleted is the last one).
Parameters
hashHash table.
nodeHash node to unlink.
Returns
Unlinked node.
Exceptions
Not InitialzedHashing not initialized.
No KeyHash key not found.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 1128 of file hash.c.

References _TPTR, hash_t::count, hash_t::dynamic, hash_lookup(), hash_self_verify, hash_table_verify(), hash_val_t_bit, hnode_t::key, LOGDIAG4CALL, hash_t::lowmark, hash_t::minsize, hnode_t::next, hnode_t::pself, and shrink_table().

Referenced by hash_delete(), and hash_node_delete().

1129 {
1130  LOGDIAG4CALL(_TPTR(hash), _TPTR(node));
1131 
1132  assert(hash_val_t_bit != 0);
1133  assert(hash_lookup(hash, node->key) == node); // Step 1
1134 
1135  if(hash->dynamic && (hash->count-1) <= hash->lowmark
1136  && hash->count > hash->minsize)
1137  {
1138  shrink_table(hash);
1139  }
1140 
1141  // Step 2
1142  if (node->next)
1143  {
1144  node->next->pself = node->pself;
1145  }
1146 
1147  // Step 3
1148  *node->pself = node->next;
1149 
1150  hash->count--;
1151 
1152  if( hash_self_verify )
1153  {
1154  assert(hash_table_verify(hash));
1155  }
1156 
1157  return node;
1158 }
bool_t dynamic
Note 12.
Definition: hash.h:281
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
hashcount_t minsize
Note 2.
Definition: hash.h:271
hnode_t * hash_lookup(hash_t *hash, const void *key)
Find a node in the hash table and return a pointer to it.
Definition: hash.c:1246
struct hnode_t * next
<Note 1
Definition: hash.h:152
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hashcount_t count
Note 8.
Definition: hash.h:277
hashcount_t lowmark
Note 5.
Definition: hash.h:274
void * key
Note 4.
Definition: hash.h:154
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
static void shrink_table(hash_t *hash)
Cut a dynamic table size in half.
Definition: hash.c:545
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
void hash_scan_begin ( hscan_t scan,
hash_t hash 
)

Reset the hash scanner (iterator).

After this call the next element retrieved by hash_scan_next() shall be the first element on the first non-empty chain.

Notes & Steps:
1. Locate the first non empty chain.
2. If an empty chain is found, remember which one it is and set the next pointer to refer to its first element.
3. Otherwise if a chain is not found, set the next pointer to NULL so that hash_scan_next() shall indicate failure.
Parameters
scanHash iterator.
hashHash table.

Definition at line 937 of file hash.c.

References hscan_t::chain, hscan_t::hash, hash_t::nchains, hscan_t::next, NULL, and hash_t::table.

Referenced by ConfigDbIterNew(), ConfigDbPrint(), ConfigSectionIterNew(), ConfigSectionPrint(), force_shrink(), hash_table_destroy(), main(), and test_hash().

938 {
939  hash_val_t nchains = hash->nchains;
940  hash_val_t chain;
941 
942  scan->hash = hash;
943 
944  // Step 1
945  for(chain = 0; chain < nchains && hash->table[chain] == 0; chain++);
946 
947  // Step 2
948  if(chain < nchains)
949  {
950  scan->chain = chain;
951  scan->next = hash->table[chain];
952  }
953 
954  // Step 3
955  else
956  {
957  scan->next = NULL;
958  }
959 }
hashcount_t nchains
Note 6.
Definition: hash.h:275
hash_t * hash
Note 1.
Definition: hash.h:305
#define NULL
null pointer
Definition: rnrconfig.h:199
hnode_t ** table
Note 1.
Definition: hash.h:270
hash_val_t chain
Note 2.
Definition: hash.h:306
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
hnode_t * next
Note 3.
Definition: hash.h:307
hnode_t* hash_scan_next ( hscan_t scan)

Retrieve the next node from the hash table.

The scanner (iterator) updates the pointer for the next invocation of hash_scan_next().

Notes & Steps:
1. Remember the next pointer in a temporary value so that it can be returned.
2. This assertion essentially checks whether the module has been properly initialized. The first point of interaction with the module should be either hash_table_create() or hash_init(), both of which set hash_val_t_bit to a non zero value.
3. If the next pointer we are returning is not NULL, then the user is allowed to call hash_scan_next() again. We prepare the new next pointer for that call right now. That way the user is allowed to delete the node we are about to return, since we will no longer be needing it to locate the next node.
4. If there is a next node in the chain (next->next), then that becomes the new next node, otherwise ...
5. We have exhausted the current chain, and must locate the next subsequent non-empty chain in the table.
6. If a non-empty chain is found, the first element of that chain becomes the new next node. Otherwise there is no new next node and we set the pointer to NULL so that the next time hash_scan_next() is called, a null pointer shall be immediately returned.
Returns
Returns next node on success, NULL if no more nodes.
Exceptions
Not InitialzedHashing not initialized.

Definition at line 998 of file hash.c.

References hscan_t::chain, hscan_t::hash, hash_val_t_bit, hash_t::nchains, hnode_t::next, hscan_t::next, NULL, and hash_t::table.

Referenced by ConfigDbPrint(), ConfigIterNext(), ConfigSectionPrint(), force_shrink(), hash_table_destroy(), main(), and test_hash().

999 {
1000  hnode_t *next = scan->next; // Step 1
1001  hash_t *hash = scan->hash;
1002  hash_val_t chain = scan->chain + 1;
1003  hash_val_t nchains = hash->nchains;
1004 
1005  assert(hash_val_t_bit != 0); // Step 2
1006 
1007  // Step 3
1008  if(next)
1009  {
1010  // Step 4
1011  if(next->next)
1012  {
1013  scan->next = next->next;
1014  }
1015  else
1016  {
1017  // Step 5
1018  while(chain < nchains && hash->table[chain] == 0)
1019  {
1020  chain++;
1021  }
1022  // Step 6
1023  if (chain < nchains)
1024  {
1025  scan->chain = chain;
1026  scan->next = hash->table[chain];
1027  }
1028  else
1029  {
1030  scan->next = NULL;
1031  }
1032  }
1033  }
1034  return next;
1035 }
hashcount_t nchains
Note 6.
Definition: hash.h:275
hash_t * hash
Note 1.
Definition: hash.h:305
#define NULL
null pointer
Definition: rnrconfig.h:199
struct hnode_t * next
<Note 1
Definition: hash.h:152
hnode_t ** table
Note 1.
Definition: hash.h:270
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
hash_val_t chain
Note 2.
Definition: hash.h:306
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
hnode_t * next
Note 3.
Definition: hash.h:307
Hash table control structure.
Definition: hash.h:267
Hash chain node structure.
Definition: hash.h:149
void hash_set_self_verify ( bool_t  selfverify)

Enable (disable) automatic self-checks during hash table modification operatations.

Parameters
selfverifyTrue to enable, false to disable.
See also
hash_table_verify()

Definition at line 1331 of file hash.c.

References hash_self_verify.

Referenced by main(), and test_hash().

1332 {
1333  hash_self_verify = selfverify;
1334 }
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hash_t* hash_table_create ( bool_t  isdynamic,
hashcount_t  minsize,
hashcount_t  maxsize,
hash_comp_t  compfun,
hash_fun_t  hashfun,
hnode_data_free_t  freedatafun 
)

Create a dynamic hash table.

Both the hash table structure and the table itself are dynamically allocated. Furthermore, the table is extendible in that it will automatically grow as its load factor increases beyond a certain threshold.

Notes & Steps:
1. If the number of bits in the hash_val_t type has not been computed yet, we do so here, because this is likely to be the first function that the user calls.
2. Allocate hash table.
3. Initialize hash table sizes. The minsize should be a power of two. The maxsize should be >= minsize. Both values will be adjusted. The high and low marks are always set to be twice the table size and half the table size respectively. When the number of nodes in the table grows beyond the high size (beyond load factor 2), it will double in size to cut the load factor down to about about 1. If the table shrinks down to or beneath load factor 0.5, it will shrink, bringing the load up to about 1. However, the table will never shrink beneath minsize even if it's emptied.
4. Allocate the table of hash chains.
5. Finish initializing the hash structure and the table. 6. This indicates that the table is dynamically allocated and dynamically resized on the fly. A table that has this value set to zero is assumed to be statically allocated and will not be resized.
7. The table of chains must be properly reset to all null pointers. 8. Verify table's correctness, if self-verification is true.
Parameters
isdynamicThe hash table is [not] automatically grow. If set to false, the hash table is initialized t be fixed at minsize and maxsize is ignored.
minsizeMinimum and initial number of hash entries that will be supported.
maxsizeMaximum number of hash entries that will be supported.
compfunHash key comparator function. NULL will use the default strcmp() wrapper.
hashfunHashing function. NULL will used the default string hashing function.
freedatafunUser key and data deallocator function. NULL will cause no user key or data to be deleted.
Returns
Newly created, empty hash table.
Exceptions
Verification FailedOnly if hash_self_verify enabled.

Definition at line 691 of file hash.c.

References _TBOOL, _TPTR, _TULONG, clear_table(), hash_t::compare, compute_bits(), compute_mask(), hash_t::count, hash_t::dynamic, hash_t::freenodedata, hash_t::hash, hash_comp_default(), hash_fun_default(), hash_self_verify, hash_table_verify(), hash_val_t_bit, hash_t::highmark, init_hash_sizes(), LOGDIAG4, LOGDIAG4CALL, hash_t::lowmark, hash_t::mask, hash_t::maxsize, hash_t::minsize, hash_t::nchains, NEW, and hash_t::table.

Referenced by ConfigDbNew(), ConfigSectionNew(), main(), and test_hash().

697 {
698  hash_t *hash;
699 
700  LOGDIAG4CALL(_TBOOL(isdynamic), _TULONG(minsize), _TULONG(maxsize),
701  _TPTR(compfun), _TPTR(hashfun), _TPTR(freedatafun));
702 
703  // Step 1
704  if( hash_val_t_bit == 0 )
705  {
706  compute_bits();
707  }
708 
709  // Step 2
710  hash = NEW(hash_t);
711 
712  // Step 3
713  init_hash_sizes(hash, minsize, maxsize);
714 
715  // Step 4
716  hash->table = (hnode_t **)new(sizeof(hnode_t *) * hash->minsize);
717 
718  // Step 5
719  hash->nchains = minsize;
720  hash->mask = compute_mask(hash->nchains);
721  hash->count = 0;
722  hash->compare = compfun ? compfun : hash_comp_default;
723  hash->hash = hashfun ? hashfun : hash_fun_default;
724  hash->freenodedata = freedatafun;
725 
726  // Step 6
727  hash->dynamic = isdynamic;
728 
729  // Step 7
730  clear_table(hash);
731 
732  // Step 8
733  if( hash_self_verify )
734  {
735  assert(hash_table_verify(hash));
736  }
737 
738  LOGDIAG4("min=%lu, max=%lu, high=%lu, low=%lu, nchains=%lu, mask=0x%lx\n",
739  hash->minsize, hash->maxsize, hash->highmark,
740  hash->lowmark, hash->nchains, hash->mask);
741 
742  return hash;
743 }
static void compute_bits()
Compute the number of bits in the hash_val_t type.
Definition: hash.c:141
bool_t dynamic
Note 12.
Definition: hash.h:281
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t nchains
Note 6.
Definition: hash.h:275
hashcount_t maxsize
Note 3.
Definition: hash.h:272
hashcount_t minsize
Note 2.
Definition: hash.h:271
static void clear_table(hash_t *hash)
Initialize the table of pointers to null.
Definition: hash.c:307
#define _TULONG(var)
unsigned long int (decimal)
Definition: log.h:580
hash_comp_t compare
Note 9.
Definition: hash.h:278
static hash_val_t hash_fun_default(const void *key)
Default hashing function over null-terminated string keys.
Definition: hash.c:263
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hashcount_t count
Note 8.
Definition: hash.h:277
#define LOGDIAG4(fmt,...)
Standard Diagnostic Level 4 logging.
Definition: log.h:386
#define NEW(T)
Allocate new type.
Definition: new.h:49
hashcount_t lowmark
Note 5.
Definition: hash.h:274
#define _TBOOL(var)
boolean
Definition: log.h:588
static hash_val_t compute_mask(hashcount_t size)
Compute a mask for a given table size.
Definition: hash.c:185
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
hnode_data_free_t freenodedata
Note 11.
Definition: hash.h:280
Hash table control structure.
Definition: hash.h:267
hash_fun_t hash
Note 10.
Definition: hash.h:279
Hash chain node structure.
Definition: hash.h:149
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
static void init_hash_sizes(hash_t *hash, hashcount_t minsize, hashcount_t maxsize)
Initialize the table size values.
Definition: hash.c:215
static int hash_comp_default(const void *key1, const void *key2)
Default hash key comparator function of null-terminated key strings.
Definition: hash.c:297
void hash_table_delete ( hash_t hash)

Frees a dynamic hash table structure.

Parameters
hashHash table.
Warning
The hash table must be empty.
Exceptions
Not InitialzedHashing not initialized.
Not EmptyHash table not empty.

Definition at line 776 of file hash.c.

References hash_isempty, hash_val_t_bit, and hash_t::table.

Referenced by hash_table_destroy().

777 {
778  assert(hash_val_t_bit != 0);
779  assert(hash_isempty(hash));
780 
781  delete(hash->table);
782  delete(hash);
783 }
hnode_t ** table
Note 1.
Definition: hash.h:270
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
#define hash_isempty(H)
Returns true if table is empty, false otherwise.
Definition: hash.h:385
void hash_table_destroy ( hash_t hash)

Delete the hash table, all of its entries, and all of the user data.

Parameters
hashHash table.

Definition at line 750 of file hash.c.

References _TPTR, hash_t::freenodedata, hash_node_fast_unlink(), hash_scan_begin(), hash_scan_next(), hash_table_delete(), hnode_destroy(), and LOGDIAG4CALL.

Referenced by ConfigDbDelete(), ConfigMainHashDeleteCb(), and main().

751 {
752  hscan_t hs;
753  hnode_t *node;
754 
755  LOGDIAG4CALL(_TPTR(hash));
756 
757  hash_scan_begin(&hs, hash);
758  while((node = hash_scan_next(&hs)))
759  {
760  hash_node_fast_unlink(hash, node);
761  hnode_destroy(node, hash->freenodedata);
762  }
763  hash_table_delete(hash);
764 }
hnode_t * hash_scan_next(hscan_t *scan)
Retrieve the next node from the hash table.
Definition: hash.c:998
hnode_t * hash_node_fast_unlink(hash_t *hash, hnode_t *node)
Fast version to unlink the given node from the hash table.
Definition: hash.c:1178
void hash_table_delete(hash_t *hash)
Frees a dynamic hash table structure.
Definition: hash.c:776
void hash_scan_begin(hscan_t *scan, hash_t *hash)
Reset the hash scanner (iterator).
Definition: hash.c:937
Hash scanner structure.
Definition: hash.h:302
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
hnode_data_free_t freenodedata
Note 11.
Definition: hash.h:280
Hash chain node structure.
Definition: hash.h:149
void hnode_destroy(hnode_t *node, hnode_data_free_t freedatafun)
Hash node and user data deallocator.
Definition: hash.c:1376
hash_t* hash_table_init ( hash_t hash,
hashcount_t  minsize,
hashcount_t  maxsize,
hash_comp_t  compfun,
hash_fun_t  hashfun,
hnode_data_free_t  freedatafun,
hnode_t **  table,
hashcount_t  nchains 
)

Initialize a user supplied hash table.

The user also supplies a table of chains which is assigned to the hash table . The table is static—it will not grow or shrink.

Notes & Steps:
1. Initialize hashing.
2. Assign hash chains. The user supplied array of pointers hopefully contains nchains nodes.
3. Fixed size. 4. We must dynamically compute the mask from the given power of two table size.
5. The user supplied table can't be assumed to contain null pointers, so we reset it here.
Warning
All data in destination hash table is overwritten.
See also
hash_table_create()
Parameters
hashThe destination hash table.
minsizeMinimum and initial number of hash entries that will be supported.
maxsizeMaximum number of hash entries that will be supported.
compfunHash key comparator function. NULL will use the default strcmp() wrapper.
hashfunHashing function. NULL will used the default string hashing function.
freedatafunUser key and data deallocator function. NULL will cause no user key or data to be deleted.
tableThe actual hash chain table to attach.
nchainsNumber of nodes in hash chain.
Returns
Hash table.
Exceptions
Bad Parameternchain not a power of 2.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 828 of file hash.c.

References _TPTR, _TULONG, clear_table(), hash_t::compare, compute_bits(), compute_mask(), hash_t::count, hash_t::dynamic, hash_t::freenodedata, hash_t::hash, hash_comp_default(), hash_fun_default(), hash_self_verify, hash_table_verify(), hash_val_t_bit, hash_t::highmark, init_hash_sizes(), is_power_of_two(), LOGDIAG4, LOGDIAG4CALL, hash_t::lowmark, hash_t::mask, hash_t::maxsize, hash_t::minsize, hash_t::nchains, and hash_t::table.

832 {
833  LOGDIAG4CALL(_TPTR(hash), _TULONG(minsize), _TULONG(maxsize),
834  _TPTR(compfun), _TPTR(hashfun), _TPTR(freedatafun),
835  _TPTR(table), _TULONG(nchains));
836 
837  // Step 1
838  if(hash_val_t_bit == 0)
839  {
840  compute_bits();
841  }
842 
843  assert(is_power_of_two(nchains));
844 
845  init_hash_sizes(hash, minsize, maxsize);
846 
847  // Step 2
848  hash->table = table;
849  hash->nchains = nchains;
850  hash->mask = compute_mask(nchains); // Step 4
851  hash->count = 0;
852  hash->compare = compfun ? compfun : hash_comp_default;
853  hash->hash = hashfun ? hashfun : hash_fun_default;
854  hash->freenodedata = freedatafun;
855  hash->dynamic = false; // Step 3
856 
857  clear_table(hash); // Step 5
858 
859  if( hash_self_verify )
860  {
861  assert (hash_table_verify(hash));
862  }
863 
864  LOGDIAG4("min=%lu, max=%lu, high=%lu, low=%lu, nchains=%lu, mask=0x%lx\n",
865  hash->minsize, hash->maxsize, hash->highmark,
866  hash->lowmark, hash->nchains, hash->mask);
867 
868  return hash;
869 }
static void compute_bits()
Compute the number of bits in the hash_val_t type.
Definition: hash.c:141
bool_t dynamic
Note 12.
Definition: hash.h:281
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t nchains
Note 6.
Definition: hash.h:275
hashcount_t maxsize
Note 3.
Definition: hash.h:272
hashcount_t minsize
Note 2.
Definition: hash.h:271
static void clear_table(hash_t *hash)
Initialize the table of pointers to null.
Definition: hash.c:307
#define _TULONG(var)
unsigned long int (decimal)
Definition: log.h:580
hash_comp_t compare
Note 9.
Definition: hash.h:278
static hash_val_t hash_fun_default(const void *key)
Default hashing function over null-terminated string keys.
Definition: hash.c:263
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
static int hash_val_t_bit
Number of bits in hashed value. Must be a power of 2.
Definition: hash.c:114
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
hashcount_t count
Note 8.
Definition: hash.h:277
#define LOGDIAG4(fmt,...)
Standard Diagnostic Level 4 logging.
Definition: log.h:386
hashcount_t lowmark
Note 5.
Definition: hash.h:274
static hash_val_t compute_mask(hashcount_t size)
Compute a mask for a given table size.
Definition: hash.c:185
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
hnode_data_free_t freenodedata
Note 11.
Definition: hash.h:280
hash_fun_t hash
Note 10.
Definition: hash.h:279
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888
static bool_t is_power_of_two(hash_val_t arg)
Verify whether the given argument is a power of two.
Definition: hash.c:163
static void init_hash_sizes(hash_t *hash, hashcount_t minsize, hashcount_t maxsize)
Initialize the table size values.
Definition: hash.c:215
static int hash_comp_default(const void *key1, const void *key2)
Default hash key comparator function of null-terminated key strings.
Definition: hash.c:297
bool_t hash_table_verify ( hash_t hash)

Verify hash table consistency.

If hash_self_verify enabled (see hash_set_self_verify()), this call is automatically called during hash table modification operations.

Notes & Steps:
1. If the hash table is dynamic, verify whether the high and low expansion/shrinkage thresholds are powers of two. 2. For each chain, verify whether the back pointers are correctly set. Count all nodes in the table, and test each hash value to see whether it is correct for the node's chain.
Returns
Returns true is the table is okay, else returns false.

Definition at line 888 of file hash.c.

References CHKEXPR_PTR, CHKEXPR_ULONG, hash_t::count, hash_t::dynamic, hash_t::highmark, is_power_of_two(), hash_t::lowmark, hash_t::mask, hash_t::nchains, hnode_t::next, and hash_t::table.

Referenced by grow_table(), hash_node_fast_unlink(), hash_node_insert(), hash_node_unlink(), hash_table_create(), hash_table_init(), and shrink_table().

889 {
890  hashcount_t count = 0;
891  hash_val_t chain;
892  hnode_t **npp;
893 
894  // Step 1
895  if (hash->dynamic)
896  {
897  CHKEXPR_ULONG(hash->lowmark, (hash->lowmark < hash->highmark), false);
898  CHKEXPR_ULONG(hash->lowmark, is_power_of_two(hash->lowmark), false);
899  CHKEXPR_ULONG(hash->highmark, is_power_of_two(hash->highmark), false);
900  }
901 
902  // Step 2
903  for(chain = 0; chain < hash->nchains; chain++)
904  {
905  for(npp = hash->table + chain; *npp; npp = &(*npp)->next)
906  {
907  CHKEXPR_PTR(npp, ((*npp)->pself == npp), false);
908  CHKEXPR_PTR(npp, (((*npp)->hkey & hash->mask) == chain), false);
909  count++;
910  }
911  }
912 
913  CHKEXPR_ULONG(hash->count, (hash->count == count), false);
914 
915  return true;
916 }
bool_t dynamic
Note 12.
Definition: hash.h:281
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t nchains
Note 6.
Definition: hash.h:275
#define CHKEXPR_PTR(val, expr,...)
check pointer
Definition: log.h:712
struct hnode_t * next
<Note 1
Definition: hash.h:152
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
hashcount_t count
Note 8.
Definition: hash.h:277
unsigned long hash_val_t
hashed value return type
Definition: hash.h:96
hashcount_t lowmark
Note 5.
Definition: hash.h:274
Hash chain node structure.
Definition: hash.h:149
static bool_t is_power_of_two(hash_val_t arg)
Verify whether the given argument is a power of two.
Definition: hash.c:163
#define CHKEXPR_ULONG(val, expr,...)
check unsigned long integer
Definition: log.h:697
hnode_t* hnode_create ( void *  data)

Create a hash table node dynamically and assign it the given data.

Parameters
dataUser data.
Returns
New hash node.

Definition at line 1343 of file hash.c.

References hnode_t::data, NEW, hnode_t::next, NULL, and hnode_t::pself.

Referenced by hash_insert().

1344 {
1345  hnode_t *node = NEW(hnode_t);
1346 
1347  node->data = data;
1348  node->next = NULL;
1349  node->pself = NULL;
1350 
1351  return node;
1352 }
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
void * data
Note 5.
Definition: hash.h:155
#define NULL
null pointer
Definition: rnrconfig.h:199
struct hnode_t * next
<Note 1
Definition: hash.h:152
#define NEW(T)
Allocate new type.
Definition: new.h:49
Hash chain node structure.
Definition: hash.h:149
void hnode_delete ( hnode_t node)

Destroy a dynamically allocated node.

User data and key are not touched.

Parameters
nodeHash node.

Definition at line 1392 of file hash.c.

1393 {
1394  delete(node);
1395 }
void hnode_destroy ( hnode_t node,
hnode_data_free_t  freedatafun 
)

Hash node and user data deallocator.

Parameters
nodeNode to deallocate.
freedatafunUser key and data deallocator. May be NULL.

Definition at line 1376 of file hash.c.

References hnode_t::data, hnode_t::key, and NULL.

Referenced by hash_delete(), hash_node_delete(), and hash_table_destroy().

1377 {
1378  if( freedatafun != NULL )
1379  {
1380  freedatafun(node->key, node->data);
1381  }
1382  delete(node);
1383 }
void * data
Note 5.
Definition: hash.h:155
#define NULL
null pointer
Definition: rnrconfig.h:199
void * key
Note 4.
Definition: hash.h:154
hnode_t* hnode_init ( hnode_t node,
void *  data 
)

Initialize a client-supplied hash node.

Parameters
nodeHash node.
dataUser data.
Returns
Same hash node.

Definition at line 1362 of file hash.c.

References hnode_t::data, hnode_t::next, NULL, and hnode_t::pself.

1363 {
1364  node->data = data;
1365  node->next = NULL;
1366  node->pself = NULL;
1367  return node;
1368 }
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
void * data
Note 5.
Definition: hash.h:155
#define NULL
null pointer
Definition: rnrconfig.h:199
struct hnode_t * next
<Note 1
Definition: hash.h:152
static void init_hash_sizes ( hash_t hash,
hashcount_t  minsize,
hashcount_t  maxsize 
)
static

Initialize the table size values.

The minimum size is adjusted to be a power of two and is guaranteed to be at least HASH_MIN_SIZE.

The maximum size adjusted to be >= minsize.

Parameters
hashHash table.
minsizeDesired minimum and initial size.
maxsizeDesired maximum size.

Definition at line 215 of file hash.c.

References HASH_MIN_SIZE, hash_t::highmark, LOGDIAG4, hash_t::lowmark, hash_t::maxsize, and hash_t::minsize.

Referenced by hash_table_create(), and hash_table_init().

218 {
219  size_t numbits, rshift, lshift;
220 
221  // number of bits in hashcount_t
222  numbits = sizeof(hashcount_t) * 8;
223 
224  // round down to the closest power of two value
225  for(rshift=0, lshift=0; rshift<numbits; ++rshift)
226  {
227  if( minsize & 0x01 )
228  {
229  lshift = rshift;
230  }
231  minsize >>= 1;
232  }
233  minsize = lshift>0? (((hashcount_t)(0x01)) << lshift):
235 
236  // absolute minimum
237  if( minsize < HASH_MIN_SIZE )
238  {
239  minsize = HASH_MIN_SIZE;
240  }
241 
242  if( maxsize < minsize )
243  {
244  maxsize = minsize;
245  }
246 
247  hash->minsize = minsize;
248  hash->maxsize = maxsize;
249  hash->lowmark = minsize / 2;
250  hash->highmark = minsize * 2;
251 
252  LOGDIAG4("minsize=%lu, maxsize=%lu, lowmark=%lu, highmark=%lu",
253  hash->minsize, hash->maxsize, hash->lowmark, hash->highmark);
254 }
hashcount_t maxsize
Note 3.
Definition: hash.h:272
hashcount_t minsize
Note 2.
Definition: hash.h:271
hashcount_t highmark
Note 4.
Definition: hash.h:273
#define HASH_MIN_SIZE
Minimum and initial size of hash table.
Definition: hash.h:104
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
#define LOGDIAG4(fmt,...)
Standard Diagnostic Level 4 logging.
Definition: log.h:386
hashcount_t lowmark
Note 5.
Definition: hash.h:274
static bool_t is_power_of_two ( hash_val_t  arg)
static

Verify whether the given argument is a power of two.

Parameters
argArgument to test.
Returns
Returns true if arg is a power of 2, false otherwise.

Definition at line 163 of file hash.c.

Referenced by compute_mask(), hash_table_init(), and hash_table_verify().

164 {
165  if( arg == 0 )
166  {
167  return false;
168  }
169 
170  while( (arg & 0x01) == 0 )
171  {
172  arg >>= 1;
173  }
174 
175  return arg == 1? true: false;
176 }
static void shrink_table ( hash_t hash)
static

Cut a dynamic table size in half.

This is done by folding together adjacent chains and populating the lower half of the table with these chains. The chains are simply spliced together. Once this is done, the whole table is reallocated to a smaller object.

Notes & Steps:
1. It is illegal to have a hash table with one slot. This would mean that hash->shift is equal to hash_val_t_bit, an illegal shift value. Also, other things could go wrong, such as hash->lowmark becoming zero.
2. Looping over each adjacent chain of pairs, the lo_chain is set to reference the lower-numbered member of the pair, whereas hi_chain is the index of the higher-numbered one.
3. The intent here is to compute a pointer to the last node of the lower chain into the lo_tail variable. If this chain is empty, lo_tail ends up with a null value.
4. If the lower chain is not empty, we have to merge chains, but only if the upper chain is also not empty. In either case, the lower chain will come first, with the upper one appended to it.
5. The first part of the join is done by having the tail node of the lower chain point to the head node of the upper chain. If the upper chain is empty, this is remains a null pointer.
6. If the upper chain is non-empty, we must do the additional house-keeping task of ensuring that the upper chain's first node's back-pointer references the tail node of the lower chain properly.
7. (defunct) 8. If the low chain is empty, but the high chain is not, then the high chain simply becomes the new chain.
9. Otherwise if both chains are empty, then the merged chain is also empty.
10. All the chain pointers are in the lower half of the table now, so we reallocate it to a smaller object. This, of course, invalidates all pointer-to-pointers which reference into the table from the first node of each chain.
11. Though it's unlikely, the reallocation may fail. In this case we pretend that the table was reallocated to a smaller object.
12. This loop performs the housekeeping task of updating the back pointers from the first node of each chain so that they reference their corresponding table entries.
13. Finally, update the various table parameters to reflect the new size.
Parameters
hashHash table.
Exceptions
Table OverflowReached system limits.
Verification FailedOnly if hash_self_verify enabled.

Definition at line 545 of file hash.c.

References _TPTR, _VARFMT, hash_self_verify, hash_table_verify(), hash_t::highmark, LOGDIAG4, LOGDIAG4CALL, hash_t::lowmark, hash_t::mask, hash_t::nchains, new_overs(), hnode_t::next, NULL, hnode_t::pself, and hash_t::table.

Referenced by hash_node_unlink().

546 {
547  hashcount_t chain, nchains;
548  size_t size;
549  hnode_t **newtable, *lo_tail, *lo_chain, *hi_chain;
550 
551  LOGDIAG4CALL(_TPTR(hash));
552 
553  // Step 1
554  assert(hash->nchains >= 2);
555 
556  // downsize chains
557  nchains = hash->nchains / 2;
558 
559  // Step 2
560  for(chain = 0; chain < nchains; chain++)
561  {
562  lo_chain = hash->table[chain];
563  hi_chain = hash->table[chain + nchains];
564 
565  // Step 3
566  for(lo_tail=lo_chain; lo_tail && lo_tail->next; lo_tail=lo_tail->next)
567  {
568  ;
569  }
570 
571  // Step 4
572  if(lo_chain)
573  {
574  // Step 5
575  lo_tail->next = hi_chain;
576 
577  // Step 6
578  if(hi_chain)
579  {
580  hi_chain->pself = &lo_tail->next;
581  }
582  }
583 
584  // Step 8
585  else if(hi_chain)
586  {
587  hash->table[chain] = hi_chain;
588  }
589 
590  // Step 9
591  else
592  {
593  hash->table[chain] = NULL;
594  }
595  }
596 
597  // Step 10
598  size = sizeof(hnode_t *) * nchains; // downsized size
599  newtable = new_overs(hash->table, size, size);
600 
601  // Step 11
602  if(newtable)
603  {
604  hash->table = newtable;
605  }
606 
607  // Step 12
608  for(chain = 0; chain < nchains; chain++)
609  {
610  if(hash->table[chain])
611  {
612  hash->table[chain]->pself = &hash->table[chain];
613  }
614  }
615 
616  // Step 13
617  hash->mask >>= 1;
618  hash->nchains = nchains;
619  hash->lowmark /= 2;
620  hash->highmark /= 2;
621 
622  LOGDIAG4(_VARFMT(hash->nchains, "%lu") ", " _VARFMT(hash->lowmark, "%lu") ", "
623  _VARFMT(hash->highmark, "%lu") ", " _VARFMT(hash->mask, "0x%lx"),
624  hash->nchains, hash->lowmark, hash->highmark, hash->mask);
625 
626  if( hash_self_verify )
627  {
628  assert(hash_table_verify(hash));
629  }
630 }
struct hnode_t ** pself
Note 3.
Definition: hash.h:153
hash_val_t mask
Note 7.
Definition: hash.h:276
hashcount_t nchains
Note 6.
Definition: hash.h:275
#define NULL
null pointer
Definition: rnrconfig.h:199
struct hnode_t * next
<Note 1
Definition: hash.h:152
hashcount_t highmark
Note 4.
Definition: hash.h:273
hnode_t ** table
Note 1.
Definition: hash.h:270
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
static bool_t hash_self_verify
Do [not] perform auto-verification after hash table operations.
Definition: hash.c:119
#define LOGDIAG4(fmt,...)
Standard Diagnostic Level 4 logging.
Definition: log.h:386
#define _VARFMT(var, fmt)
log Variable Format.
Definition: log.h:555
void * new_overs(void *pSrc, size_t sizeDup, size_t sizeNew)
Allocate and duplicate.
Definition: new.c:112
hashcount_t lowmark
Note 5.
Definition: hash.h:274
#define _TPTR(var)
pointer
Definition: log.h:587
#define LOGDIAG4CALL(...)
Standard Diagnostic Level 4 function call tracing.
Definition: log.h:442
Hash chain node structure.
Definition: hash.h:149
bool_t hash_table_verify(hash_t *hash)
Verify hash table consistency.
Definition: hash.c:888