Skip to content

Commit 7fe5632

Browse files
committed
Merge pull request #97 from hintjens/master
Added load/save methods to zhash class
2 parents 9e6c0ff + 23f7b6d commit 7fe5632

File tree

4 files changed

+135
-39
lines changed

4 files changed

+135
-39
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/zclock.c

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,6 @@ The zclock class provides essential sleep and system time functions, used
2727
to slow down threads for testing, and calculate timers for polling. Wraps
2828
the non-portable system calls in a simple portable API.
2929
@discuss
30-
This class contains some small surprises. Most amazing, win32 did an API
31-
better than POSIX. The win32 Sleep() call is not only a neat 1-liner, it
32-
also sleeps for milliseconds, whereas the POSIX call asks us to think in
33-
terms of nanoseconds, which is insane. I've decided every single man page
34-
for this library will say "insane" at least once. Anyhow, milliseconds
35-
are a concept we can deal with. Seconds are too fat, nanoseconds too
36-
tiny, but milliseconds are just right for slices of time we want to work
37-
with at the 0MQ scale. zclock doesn't give you objects to work with, we
38-
like the czmq class model but we're not insane. There, got it in again.
3930
The Win32 Sleep() call defaults to 16ms resolution unless the system timer
4031
resolution is increased with a call to timeBeginPeriod() permitting 1ms
4132
granularity.
@@ -52,9 +43,10 @@ granularity.
5243
static int64_t
5344
s_filetime_to_msec (const FILETIME *ft)
5445
{
55-
// As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
56-
// ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
57-
// prevent alignment faults on 64-bit Windows).
46+
// As per Windows documentation for FILETIME, copy the resulting FILETIME
47+
// structure to a ULARGE_INTEGER structure using memcpy (using memcpy
48+
// instead of direct assignment can prevent alignment faults on 64-bit
49+
// Windows).
5850
ULARGE_INTEGER dateTime;
5951
memcpy (&dateTime, ft, sizeof (dateTime));
6052

@@ -75,11 +67,12 @@ zclock_sleep (int msecs)
7567
t.tv_nsec = (msecs % 1000) * 1000000;
7668
nanosleep (&t, NULL);
7769
#elif (defined (__WINDOWS__))
78-
// Windows XP/2000: A value of zero causes the thread to relinquish the
79-
// remainder of its time slice to any other thread of equal priority that is
80-
// ready to run. If there are no other threads of equal priority ready to run,
81-
// the function returns immediately, and the thread continues execution. This
82-
// behavior changed starting with Windows Server 2003.
70+
// Windows XP/2000: A value of zero causes the thread to relinquish the
71+
// remainder of its time slice to any other thread of equal priority that
72+
// is ready to run. If there are no other threads of equal priority ready
73+
// to run, the function returns immediately, and the thread continues
74+
// execution. This behavior changed starting with Windows Server 2003.
75+
8376
# if defined (NTDDI_VERSION) && defined (NTDDI_WS03) && (NTDDI_VERSION >= NTDDI_WS03)
8477
Sleep (msecs);
8578
# else

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");

src/zlist.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ s_compare (void *item1, void *item2)
350350
return false;
351351
}
352352

353+
353354
// --------------------------------------------------------------------------
354355
// Set list for automatic item destruction
355356

@@ -360,6 +361,7 @@ zlist_autofree (zlist_t *self)
360361
self->autofree = true;
361362
}
362363

364+
363365
// --------------------------------------------------------------------------
364366
// Runs selftest of class
365367

0 commit comments

Comments
 (0)