Skip to content

Commit 23f7b6d

Browse files
committed
Added zhash load/save and autofree methods
1 parent 4163e94 commit 23f7b6d

File tree

2 files changed

+123
-22
lines changed

2 files changed

+123
-22
lines changed

include/zhash.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ CZMQ_EXPORT zlist_t *
100100
CZMQ_EXPORT int
101101
zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument);
102102

103+
// Save hash table to a text file in name=value format. Hash values must be
104+
// printable strings; keys may not contain '=' character. Returns 0 if OK,
105+
// else -1 if a file error occurred.
106+
CZMQ_EXPORT int
107+
zhash_save (zhash_t *self, char *filename);
108+
109+
// Load hash table from a text file in name=value format; hash table must
110+
// already exist. Hash values must printable strings; keys may not contain
111+
// '=' character. Returns 0 if OK, else -1 if a file was not readable.
112+
CZMQ_EXPORT int
113+
zhash_load (zhash_t *self, char *filename);
114+
115+
// Set hash for automatic value destruction
116+
CZMQ_EXPORT void
117+
zhash_autofree (zhash_t *self);
118+
103119
// Self test of this class
104120
void
105121
zhash_test (int verbose);

src/zhash.c

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,23 @@
4646
// Hash item, used internally only
4747

4848
typedef struct _item_t {
49-
void
50-
*value; // Opaque item value
51-
struct _item_t
52-
*next; // Next item in the hash slot
53-
qbyte
54-
index; // Index of item in table
55-
char
56-
*key; // Item's original key
57-
zhash_free_fn
58-
*free_fn; // Value free function if any
49+
void *value; // Opaque item value
50+
struct _item_t *next; // Next item in the hash slot
51+
qbyte index; // Index of item in table
52+
char *key; // Item's original key
53+
zhash_free_fn *free_fn; // Value free function if any
5954
} item_t;
6055

6156

6257
// ---------------------------------------------------------------------
6358
// Structure of our class
6459

6560
struct _zhash {
66-
size_t
67-
size; // Current size of hash table
68-
size_t
69-
limit; // Current hash table limit
70-
item_t
71-
**items; // Array of items
72-
uint
73-
cached_index; // Avoids duplicate hash calculations
61+
size_t size; // Current size of hash table
62+
size_t limit; // Current hash table limit
63+
item_t **items; // Array of items
64+
uint cached_index; // Avoids duplicate hash calculations
65+
bool autofree; // If true, free values in destructor
7466
};
7567

7668

@@ -81,10 +73,8 @@ struct _zhash {
8173
static uint
8274
s_item_hash (const char *key, size_t limit)
8375
{
84-
uint
85-
key_hash = 0;
86-
8776
// Modified Bernstein hashing function
77+
uint key_hash = 0;
8878
while (*key)
8979
key_hash = 33 * key_hash ^ *key++;
9080
key_hash %= limit;
@@ -162,6 +152,10 @@ s_item_destroy (zhash_t *self, item_t *item, bool hard)
162152
if (hard) {
163153
if (item->free_fn)
164154
(item->free_fn) (item->value);
155+
else
156+
if (self->autofree)
157+
free (item->value);
158+
165159
free (item->key);
166160
free (item);
167161
}
@@ -271,6 +265,9 @@ zhash_update (zhash_t *self, const char *key, void *value)
271265
if (item) {
272266
if (item->free_fn)
273267
(item->free_fn) (item->value);
268+
else
269+
if (self->autofree)
270+
free (item->value);
274271
item->value = value;
275272
}
276273
else
@@ -386,20 +383,21 @@ zhash_dup (zhash_t *self)
386383
return NULL;
387384

388385
zhash_t *copy = zhash_new ();
386+
zhash_autofree (copy);
389387
if (copy) {
390388
uint index;
391389
for (index = 0; index != self->limit; index++) {
392390
item_t *item = self->items [index];
393391
while (item) {
394392
zhash_insert (copy, item->key, strdup (item->value));
395-
zhash_freefn (copy, item->key, free);
396393
item = item->next;
397394
}
398395
}
399396
}
400397
return copy;
401398
}
402399

400+
403401
// --------------------------------------------------------------------------
404402
// Return keys for items in table
405403

@@ -448,6 +446,76 @@ zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument)
448446
}
449447

450448

449+
// --------------------------------------------------------------------------
450+
// Save hash table to a text file in name=value format
451+
// Hash values must be printable strings; keys may not contain '=' character
452+
// Returns 0 if OK, else -1 if a file error occurred
453+
454+
int
455+
zhash_save (zhash_t *self, char *filename)
456+
{
457+
assert (self);
458+
459+
FILE *handle = fopen (filename, "w");
460+
if (!handle)
461+
return -1; // Failed to create file
462+
463+
uint index;
464+
for (index = 0; index != self->limit; index++) {
465+
item_t *item = self->items [index];
466+
while (item) {
467+
fprintf (handle, "%s=%s\n", item->key, (char *) item->value);
468+
item = item->next;
469+
}
470+
}
471+
fclose (handle);
472+
return 0;
473+
}
474+
475+
476+
// --------------------------------------------------------------------------
477+
// Load hash table from a text file in name=value format; hash table must
478+
// already exist. Hash values must printable strings; keys may not contain
479+
// '=' character. Returns 0 if OK, else -1 if a file was not readable.
480+
481+
int
482+
zhash_load (zhash_t *self, char *filename)
483+
{
484+
assert (self);
485+
zhash_autofree (self);
486+
487+
FILE *handle = fopen (filename, "r");
488+
if (!handle)
489+
return -1; // Failed to create file
490+
491+
char buffer [1024];
492+
while (fgets (buffer, 1024, handle)) {
493+
// Buffer may end in newline, which we don't want
494+
if (buffer [strlen (buffer) - 1] == '\n')
495+
buffer [strlen (buffer) - 1] = 0;
496+
// Split at equals, if any
497+
char *equals = strchr (buffer, '=');
498+
if (!equals)
499+
break; // Some error, stop parsing it
500+
*equals++ = 0;
501+
zhash_update (self, buffer, strdup (equals));
502+
}
503+
fclose (handle);
504+
return 0;
505+
}
506+
507+
508+
// --------------------------------------------------------------------------
509+
// Set hash for automatic value destruction
510+
511+
void
512+
zhash_autofree (zhash_t *self)
513+
{
514+
assert (self);
515+
self->autofree = true;
516+
}
517+
518+
451519
// --------------------------------------------------------------------------
452520
// Runs selftest of class
453521
// TODO: add unit test for free_fn, foreach
@@ -509,8 +577,25 @@ zhash_test (int verbose)
509577
// Test dup method
510578
zhash_t *copy = zhash_dup (hash);
511579
assert (zhash_size (copy) == 4);
580+
item = zhash_lookup (copy, "LIVEBEEF");
581+
assert (item);
582+
assert (streq (item, "dead beef"));
512583
zhash_destroy (&copy);
513584

585+
// Test save and load
586+
zhash_save (hash, ".cache");
587+
copy = zhash_new ();
588+
zhash_load (copy, ".cache");
589+
item = zhash_lookup (copy, "LIVEBEEF");
590+
assert (item);
591+
assert (streq (item, "dead beef"));
592+
zhash_destroy (&copy);
593+
#if (defined (WIN32))
594+
DeleteFile (".cache");
595+
#else
596+
unlink (".cache");
597+
#endif
598+
514599
// Delete a item
515600
zhash_delete (hash, "LIVEBEEF");
516601
item = zhash_lookup (hash, "LIVEBEEF");

0 commit comments

Comments
 (0)