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

Example of using a librnr hash table. More...

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.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.

Typedefs

typedef char input_t[256]
 Working input buffer.
 

Functions

static int tokenize (char *string,...)
 Tokenize input. More...
 
static void del_node_data (void *key, void *val)
 Delete node data - both key and value are dynamically allocated. More...
 
static void force_grow (hash_t *h)
 Force table to grow by feeding the table random entries. More...
 
static void force_shrink (hash_t *h)
 Force table to shink by deleting table random entries. More...
 
int main (int argc, char *argv[])
 Example main. More...
 

Variables

static char * Colorado14ers [][2]
 Colorado's 14,000+ foot mountains. More...
 
static int MtnCounter = 0
 Make random keys unique.
 

Detailed Description

Example of using a librnr hash table.

LastChangedDate
2011-11-18 13:30:34 -0700 (Fri, 18 Nov 2011)
Rev
1577
Author
Robin Knight (robin.nosp@m..kni.nosp@m.ght@r.nosp@m.oadn.nosp@m.arrow.nosp@m.s.co.nosp@m.m)

Definition in file example_hash.c.

Function Documentation

static void del_node_data ( void *  key,
void *  val 
)
static

Delete node data - both key and value are dynamically allocated.

Parameters
keyData key.
valData value.

Definition at line 110 of file example_hash.c.

Referenced by force_grow(), and main().

111 {
112  delete(key);
113  delete(val);
114 }
static void force_grow ( hash_t h)
static

Force table to grow by feeding the table random entries.

Parameters
hPointer to hash table.

Definition at line 151 of file example_hash.c.

References arraysize, Colorado14ers, del_node_data(), hash_count, hash_insert(), hash_size, hash_t::highmark, MtnCounter, and new_strdup().

Referenced by main().

152 {
153  hashcount_t count, size;
154  size_t num_mtns = arraysize(Colorado14ers);
155  int mtn;
156  char buf[64];
157  char *key, *val;
158 
159  count = hash_count(h);
160  size = hash_size(h);
161 
162  printf(" starting count=%lu, table size=%lu\n", count, size);
163 
164  // tables grows at highwater mark
165  size = h->highmark;
166 
167  while( count++ < size )
168  {
169  mtn = (int)(random() % (long int)num_mtns);
170  sprintf(buf, "%s(%d)", Colorado14ers[mtn][0], MtnCounter++);
171  key = new_strdup(buf);
172  val = new_strdup(Colorado14ers[mtn][1]);
173 
174  if( !hash_insert(h, key, val) )
175  {
176  puts("hash_insert failed");
177  del_node_data(key, val);
178  return;
179  }
180  else
181  {
182  printf(" added %s -> %s\n", key, val);
183  }
184  }
185 
186  count = hash_count(h);
187  size = hash_size(h);
188 
189  printf(" ending count=%lu, table size=%lu\n", count, size);
190 }
char * new_strdup(const char *s)
Duplicate a string.
Definition: new.c:176
static void del_node_data(void *key, void *val)
Delete node data - both key and value are dynamically allocated.
Definition: example_hash.c:110
static int MtnCounter
Make random keys unique.
Definition: example_hash.c:144
#define hash_size(H)
Returns size of hash table.
Definition: hash.h:397
hashcount_t highmark
Note 4.
Definition: hash.h:273
#define arraysize(array)
array size, i.e. number of array entries
Definition: rnrconfig.h:259
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
#define hash_count(H)
Returns number of entires in hash table.
Definition: hash.h:391
bool_t hash_insert(hash_t *hash, void *key, void *data)
Insert user data with the given key into the hash table.
Definition: hash.c:1283
static char * Colorado14ers[][2]
Colorado&#39;s 14,000+ foot mountains.
Definition: example_hash.c:121
static void force_shrink ( hash_t h)
static

Force table to shink by deleting table random entries.

Parameters
hPointer to hash table.

Definition at line 197 of file example_hash.c.

References hash_count, hash_node_delete(), hash_scan_begin(), hash_scan_next(), hash_size, hnode_get, hnode_getkey, hash_t::lowmark, and NULL.

Referenced by main().

198 {
199  hashcount_t count, size;
200  hscan_t hs;
201  hnode_t *hn;
202  char *key, *val;
203 
204  count = hash_count(h);
205  size = hash_size(h);
206 
207  printf(" starting count=%lu, table size=%lu\n", count, size);
208 
209  // tables shrinks at lowwater mark
210  size = h->lowmark;
211 
212  hash_scan_begin(&hs, h);
213 
214  // delete first count nodes
215  while( ((hn = hash_scan_next(&hs)) != NULL) && (count-- > size) )
216  {
217  key = (char *)hnode_getkey(hn);
218  val = (char *)hnode_get(hn);
219  printf(" deleted %s -> %s\n", key, val);
220  hash_node_delete(h, hn);
221  }
222 
223  count = hash_count(h);
224  size = hash_size(h);
225 
226  printf(" ending count=%lu, table size=%lu\n", count, size);
227 }
#define hnode_getkey(N)
Get hash node hash key.
Definition: hash.h:409
hnode_t * hash_scan_next(hscan_t *scan)
Retrieve the next node from the hash table.
Definition: hash.c:998
#define NULL
null pointer
Definition: rnrconfig.h:199
#define hash_size(H)
Returns size of hash table.
Definition: hash.h:397
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
hashcount_t lowmark
Note 5.
Definition: hash.h:274
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 hnode_get(N)
Get hash node user data.
Definition: hash.h:403
Hash chain node structure.
Definition: hash.h:149
void hash_node_delete(hash_t *hash, hnode_t *node)
Unlink and delete a hash node from the hash table.
Definition: hash.c:1217
#define hash_count(H)
Returns number of entires in hash table.
Definition: hash.h:391
int main ( int  argc,
char *  argv[] 
)

Example main.

Parameters
argcCommand-line argument count.
argvCommand-line argument list.
Exit Status:
Program exits with 0 success, > 0 on failure.

Definition at line 238 of file example_hash.c.

References del_node_data(), force_grow(), force_shrink(), hash_count, hash_insert(), hash_lookup(), hash_node_delete(), hash_scan_begin(), hash_scan_next(), hash_set_self_verify(), hash_size, hash_table_create(), hash_table_destroy(), HASHCOUNT_T_MAX, hnode_get, hnode_getkey, LOG_SET_THRESHOLD(), new_strdup(), NULL, and tokenize().

239 {
240  input_t in;
241  hash_t *h = NULL;
242  hnode_t *hn;
243  hscan_t hs;
244  char *tok1, *tok2;
245  char *key, *val;
246  int n;
247 
248  char *help =
249  "n create new empty hash table\n"
250  "x delete entire hash table\n"
251  "a <key> <val> add value to hash table\n"
252  "d <key> delete value from hash table\n"
253  "l <key> lookup value in hash table\n"
254  "c show counts: number of entries and table size\n"
255  "t dump whole hash table\n"
256  "+ force increase hash table (by auto-adding)\n"
257  "- force decrease hash table (by auto-deleting)\n"
258  "v <level> set logging verbosity level 0-4\n"
259  "q quit";
260 
261 
262  puts("Hashing example (enter '?' for list of commands)");
263 
264  // process user commands
265  for(;;)
266  {
267  printf("hash> ");
268 
269  // read user input
270  if( !fgets(in, (int)sizeof(input_t), stdin) )
271  {
272  break;
273  }
274 
275  // execute command
276  switch( in[0] )
277  {
278  // help
279  case '?':
280  puts(help);
281  break;
282 
283  // create new hash table
284  case 'n':
285  if( h != NULL )
286  {
287  printf("table exists, delete first\n");
288  }
289  else
290  {
291  h = hash_table_create(
292  true, // dynamic table sizing
293  (hashcount_t)4, // minimum size
294  HASHCOUNT_T_MAX, // maximum size
295  NULL, // use default comparator function
296  NULL, // use default hashing function
297  del_node_data); // hash node data deletion function
298 
299  hash_set_self_verify(true); // off by default
300  }
301  break;
302 
303  // delete hash table and all user data
304  case 'x':
305  if( h == NULL )
306  {
307  printf("no table\n");
308  }
309  else
310  {
312  h = NULL;
313  }
314  break;
315 
316  // add hash table entry
317  case 'a':
318  if( h == NULL )
319  {
320  printf("no hash table\n");
321  }
322  else if(tokenize(in+1, &tok1, &tok2, (char **) 0) != 2)
323  {
324  puts("what?");
325  }
326  else
327  {
328  // new key and value
329  key = new_strdup(tok1);
330  val = new_strdup(tok2);
331 
332  // insert into hash table, automatically allocating hnode_t
333  if( !hash_insert(h, key, val) )
334  {
335  puts("hash_insert failed");
336  del_node_data(key, val);
337  }
338  }
339  break;
340 
341  // delete hash table entry
342  case 'd':
343  if( h == NULL )
344  {
345  printf("no hash table\n");
346  }
347  else if(tokenize(in+1, &tok1, (char **)0) != 1)
348  {
349  puts("what?");
350  }
351  else if( (hn = hash_lookup(h, tok1)) == NULL )
352  {
353  puts("hash_lookup failed");
354  }
355  else
356  {
357  key = (char *)hnode_getkey(hn);
358  val = (char *)hnode_get(hn);
359  printf("deleted %s -> %s\n", key, val);
360  hash_node_delete(h, hn);
361  }
362  break;
363 
364  // lookup hash table entry
365  case 'l':
366  if( h == NULL )
367  {
368  printf("no hash table\n");
369  }
370  else if(tokenize(in+1, &tok1, (char **) 0) != 1)
371  {
372  puts("what?");
373  }
374  else if( (hn = hash_lookup(h, tok1)) == NULL )
375  {
376  puts("hash_lookup failed");
377  }
378  else
379  {
380  val = hnode_get(hn);
381  printf("%s -> %s\n", tok1, val);
382  }
383  break;
384 
385  // get current number of hash table entries and current table size
386  case 'c':
387  if( h == NULL )
388  {
389  printf("no hash table\n");
390  }
391  else
392  {
393  printf("count=%lu, size=%lu\n",
394  (unsigned long)hash_count(h), (unsigned long)hash_size(h));
395  }
396  break;
397 
398  // dump hash table entries
399  case 't':
400  if( h == NULL )
401  {
402  printf("no hash table\n");
403  }
404  else
405  {
406  hash_scan_begin(&hs, h);
407  while( (hn = hash_scan_next(&hs)) != NULL )
408  {
409  printf("%s -> %s\n", (char *)hnode_getkey(hn),
410  (char *)hnode_get(hn));
411  }
412  }
413  break;
414 
415  // force hash table to grow
416  case '+':
417  if( h == NULL )
418  {
419  printf("no hash table\n");
420  }
421  else
422  {
423  force_grow(h);
424  }
425  break;
426 
427  // force hash table to shrink
428  case '-':
429  if( h == NULL )
430  {
431  printf("no hash table\n");
432  }
433  else
434  {
435  force_shrink(h);
436  }
437  break;
438 
439  // logging level
440  case 'v':
441  if( tokenize(in+1, &tok1, (char **)0) != 1 )
442  {
443  puts("what?");
444  }
445  else
446  {
447  n = atoi(tok1);
449  }
450  break;
451 
452  // quit
453  case 'q':
454  exit(0);
455  break;
456 
457  // null command
458  case '\0':
459  case '\n':
460  break;
461 
462  // input error
463  default:
464  puts("?");
465  break;
466  }
467  }
468 
469  return 0;
470 }
#define hnode_getkey(N)
Get hash node hash key.
Definition: hash.h:409
static void force_grow(hash_t *h)
Force table to grow by feeding the table random entries.
Definition: example_hash.c:151
#define HASHCOUNT_T_MAX
Maximum maximum hash table size.
Definition: hash.h:81
hnode_t * hash_scan_next(hscan_t *scan)
Retrieve the next node from the hash table.
Definition: hash.c:998
char * new_strdup(const char *s)
Duplicate a string.
Definition: new.c:176
static void del_node_data(void *key, void *val)
Delete node data - both key and value are dynamically allocated.
Definition: example_hash.c:110
#define NULL
null pointer
Definition: rnrconfig.h:199
char input_t[256]
Working input buffer.
Definition: example_hash.c:57
int LOG_SET_THRESHOLD(int nLevel)
Set new logging threshold level.
Definition: log.c:96
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
#define hash_size(H)
Returns size of hash table.
Definition: hash.h:397
void hash_set_self_verify(bool_t selfverify)
Enable (disable) automatic self-checks during hash table modification operatations.
Definition: hash.c:1331
unsigned long hashcount_t
maximum hash table size type
Definition: hash.h:94
static void force_shrink(hash_t *h)
Force table to shink by deleting table random entries.
Definition: example_hash.c:197
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 hnode_get(N)
Get hash node user data.
Definition: hash.h:403
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.
Definition: hash.c:691
Hash table control structure.
Definition: hash.h:267
Hash chain node structure.
Definition: hash.h:149
void hash_node_delete(hash_t *hash, hnode_t *node)
Unlink and delete a hash node from the hash table.
Definition: hash.c:1217
#define hash_count(H)
Returns number of entires in hash table.
Definition: hash.h:391
bool_t hash_insert(hash_t *hash, void *key, void *data)
Insert user data with the given key into the hash table.
Definition: hash.c:1283
void hash_table_destroy(hash_t *hash)
Delete the hash table, all of its entries, and all of the user data.
Definition: hash.c:750
static int tokenize(char *string,...)
Tokenize input.
Definition: example_hash.c:68
static int tokenize ( char *  string,
  ... 
)
static

Tokenize input.

Parameters
stringInput string to parse.
[out]...Variable argument list of char** arguments terminated by a last NULL argument.
Returns
Number of tokens.

Definition at line 68 of file example_hash.c.

Referenced by main().

69 {
70  char **tokptr;
71  va_list arglist;
72  int tokcount = 0;
73 
74  va_start(arglist, string);
75  tokptr = va_arg(arglist, char **);
76  while(tokptr)
77  {
78  while(*string && isspace((int)*string))
79  {
80  string++;
81  }
82  if(!*string)
83  {
84  break;
85  }
86  *tokptr = string;
87  while(*string && !isspace((int)*string))
88  {
89  string++;
90  }
91  tokptr = va_arg(arglist, char **);
92  tokcount++;
93  if(!*string)
94  {
95  break;
96  }
97  *string++ = 0;
98  }
99  va_end(arglist);
100 
101  return tokcount;
102 }

Variable Documentation

char* Colorado14ers[][2]
static
Initial value:
=
{
{"mt_elbert", "14,433"},
{"mt_massive", "14,421"},
{"mt_harvard", "14,420"},
{"blanca_peak", "14,345"},
{"la_plata_peak", "14,336"},
{"uncompahgre_peak", "14,309"},
{"crestone_peak", "14,294"},
{"mt_lincoln", "14,286"},
{"grays_peak", "14,270"},
{"mt_antero", "14,269"},
{"torreys_peak", "14,267"},
{"castle_peak", "14,265"},
{"quandary_peak", "14,265"},
{"mt_evans", "14,264"},
{"longs_peak", "14,255"},
{"mt_wilson", "14,246"}
}

Colorado's 14,000+ foot mountains.

N.B. there are 53 of them, I'm stopping at the highest 16.

Definition at line 121 of file example_hash.c.

Referenced by force_grow().