zhash.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 This software was developed in the APRIL Robotics Lab under the
4 direction of Edwin Olson, ebolson@umich.edu. This software may be
5 available under alternative licensing terms; contact the address above.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation
12  and/or other materials provided with the distribution.
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 The views and conclusions contained in the software and documentation are those
24 of the authors and should not be interpreted as representing official policies,
25 either expressed or implied, of the Regents of The University of Michigan.
26 */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 
33 #include "zhash.h"
34 
35 // force a rehash when our capacity is less than this many times the size
36 #define ZHASH_FACTOR_CRITICAL 2
37 
38 // When resizing, how much bigger do we want to be? (should be greater than _CRITICAL)
39 #define ZHASH_FACTOR_REALLOC 4
40 
41 struct zhash
42 {
43  size_t keysz, valuesz;
44  int entrysz; // valid byte (1) + keysz + values
45 
46  uint32_t(*hash)(const void *a);
47 
48  // returns 1 if equal
49  int(*equals)(const void *a, const void *b);
50 
51  int size; // # of items in hash table
52 
53  char *entries; // each entry of size entrysz;
54  int nentries; // how many entries are allocated? Never 0.
55 };
56 
57 zhash_t *zhash_create_capacity(size_t keysz, size_t valuesz,
58  uint32_t(*hash)(const void *a), int(*equals)(const void *a, const void*b),
59  int capacity)
60 {
61  assert(hash != NULL);
62  assert(equals != NULL);
63 
64  // resize...
65  int _nentries = ZHASH_FACTOR_REALLOC * capacity;
66  if (_nentries < 8)
67  _nentries = 8;
68 
69  // to a power of 2.
70  int nentries = _nentries;
71  if ((nentries & (nentries - 1)) != 0) {
72  nentries = 8;
73  while (nentries < _nentries)
74  nentries *= 2;
75  }
76 
77  zhash_t *zh = (zhash_t*) calloc(1, sizeof(zhash_t));
78  zh->keysz = keysz;
79  zh->valuesz = valuesz;
80  zh->hash = hash;
81  zh->equals = equals;
82  zh->nentries = nentries;
83 
84  zh->entrysz = 1 + zh->keysz + zh->valuesz;
85 
86  zh->entries = calloc(zh->nentries, zh->entrysz);
87 
88  return zh;
89 }
90 
91 zhash_t *zhash_create(size_t keysz, size_t valuesz,
92  uint32_t(*hash)(const void *a), int(*equals)(const void *a, const void *b))
93 {
94  return zhash_create_capacity(keysz, valuesz, hash, equals, 8);
95 }
96 
98 {
99  if (zh == NULL)
100  return;
101 
102  free(zh->entries);
103  free(zh);
104 }
105 
106 int zhash_size(const zhash_t *zh)
107 {
108  return zh->size;
109 }
110 
112 {
113  memset(zh->entries, 0, zh->nentries * zh->entrysz);
114  zh->size = 0;
115 }
116 
117 int zhash_get_volatile(const zhash_t *zh, const void *key, void *out_value)
118 {
119  uint32_t code = zh->hash(key);
120  uint32_t entry_idx = code & (zh->nentries - 1);
121 
122  while (zh->entries[entry_idx * zh->entrysz]) {
123  void *this_key = &zh->entries[entry_idx * zh->entrysz + 1];
124  if (zh->equals(key, this_key)) {
125  *((void**) out_value) = &zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz];
126  return 1;
127  }
128 
129  entry_idx = (entry_idx + 1) & (zh->nentries - 1);
130  }
131 
132  return 0;
133 }
134 
135 int zhash_get(const zhash_t *zh, const void *key, void *out_value)
136 {
137  void *tmp;
138  if (zhash_get_volatile(zh, key, &tmp)) {
139  memcpy(out_value, tmp, zh->valuesz);
140  return 1;
141  }
142 
143  return 0;
144 }
145 
146 int zhash_put(zhash_t *zh, const void *key, const void *value, void *oldkey, void *oldvalue)
147 {
148  uint32_t code = zh->hash(key);
149  uint32_t entry_idx = code & (zh->nentries - 1);
150 
151  while (zh->entries[entry_idx * zh->entrysz]) {
152  void *this_key = &zh->entries[entry_idx * zh->entrysz + 1];
153  void *this_value = &zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz];
154 
155  if (zh->equals(key, this_key)) {
156  // replace
157  if (oldkey)
158  memcpy(oldkey, this_key, zh->keysz);
159  if (oldvalue)
160  memcpy(oldvalue, this_value, zh->valuesz);
161  memcpy(this_key, key, zh->keysz);
162  memcpy(this_value, value, zh->valuesz);
163  zh->entries[entry_idx * zh->entrysz] = 1; // mark valid
164  return 1;
165  }
166 
167  entry_idx = (entry_idx + 1) & (zh->nentries - 1);
168  }
169 
170  // add the entry
171  zh->entries[entry_idx * zh->entrysz] = 1;
172  memcpy(&zh->entries[entry_idx * zh->entrysz + 1], key, zh->keysz);
173  memcpy(&zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz], value, zh->valuesz);
174  zh->size++;
175 
176  if (zh->nentries < ZHASH_FACTOR_CRITICAL * zh->size) {
177  zhash_t *newhash = zhash_create_capacity(zh->keysz, zh->valuesz,
178  zh->hash, zh->equals,
179  zh->size);
180 
181  for (int idx = 0; idx < zh->nentries; idx++) {
182 
183  if (zh->entries[idx * zh->entrysz]) {
184  void *this_key = &zh->entries[idx * zh->entrysz + 1];
185  void *this_value = &zh->entries[idx * zh->entrysz + 1 + zh->keysz];
186  if (zhash_put(newhash, this_key, this_value, NULL, NULL))
187  assert(0); // shouldn't already be present.
188  }
189  }
190 
191  // play switch-a-roo
192  zhash_t tmp;
193  memcpy(&tmp, zh, sizeof(zhash_t));
194  memcpy(zh, newhash, sizeof(zhash_t));
195  memcpy(newhash, &tmp, sizeof(zhash_t));
196  zhash_destroy(newhash);
197  }
198 
199  return 0;
200 }
201 
202 int zhash_remove(zhash_t *zh, const void *key, void *old_key, void *old_value)
203 {
204  uint32_t code = zh->hash(key);
205  uint32_t entry_idx = code & (zh->nentries - 1);
206 
207  while (zh->entries[entry_idx * zh->entrysz]) {
208  void *this_key = &zh->entries[entry_idx * zh->entrysz + 1];
209  void *this_value = &zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz];
210 
211  if (zh->equals(key, this_key)) {
212  if (old_key)
213  memcpy(old_key, this_key, zh->keysz);
214  if (old_value)
215  memcpy(old_value, this_value, zh->valuesz);
216 
217  // mark this entry as available
218  zh->entries[entry_idx * zh->entrysz] = 0;
219  zh->size--;
220 
221  // reinsert any consecutive entries that follow
222  while (1) {
223  entry_idx = (entry_idx + 1) & (zh->nentries - 1);
224 
225  if (zh->entries[entry_idx * zh->entrysz]) {
226  // completely remove this entry
227  char *tmp = malloc(sizeof(char)*zh->entrysz);
228  memcpy(tmp, &zh->entries[entry_idx * zh->entrysz], zh->entrysz);
229  zh->entries[entry_idx * zh->entrysz] = 0;
230  zh->size--;
231  // reinsert it
232  if (zhash_put(zh, &tmp[1], &tmp[1+zh->keysz], NULL, NULL))
233  assert(0);
234  free(tmp);
235  } else {
236  break;
237  }
238  }
239  return 1;
240  }
241 
242  entry_idx = (entry_idx + 1) & (zh->nentries - 1);
243  }
244 
245  return 0;
246 }
247 
249 {
250  zhash_t *newhash = zhash_create_capacity(zh->keysz, zh->valuesz,
251  zh->hash, zh->equals,
252  zh->size);
253 
254  for (int entry_idx = 0; entry_idx < zh->nentries; entry_idx++) {
255  if (zh->entries[entry_idx * zh->entrysz]) {
256  void *this_key = &zh->entries[entry_idx * zh->entrysz + 1];
257  void *this_value = &zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz];
258  if (zhash_put(newhash, this_key, this_value, NULL, NULL))
259  assert(0); // shouldn't already be present.
260  }
261  }
262 
263  return newhash;
264 }
265 
266 int zhash_contains(const zhash_t *zh, const void *key)
267 {
268  void *tmp;
269  return zhash_get_volatile(zh, key, &tmp);
270 }
271 
273 {
274  zit->zh = zh;
275  zit->czh = zh;
276  zit->last_entry = -1;
277 }
278 
280 {
281  zit->zh = NULL;
282  zit->czh = zh;
283  zit->last_entry = -1;
284 }
285 
286 int zhash_iterator_next_volatile(zhash_iterator_t *zit, void *outkey, void *outvalue)
287 {
288  const zhash_t *zh = zit->czh;
289 
290  while (1) {
291  if (zit->last_entry + 1 >= zh->nentries)
292  return 0;
293 
294  zit->last_entry++;
295 
296  if (zh->entries[zit->last_entry * zh->entrysz]) {
297  void *this_key = &zh->entries[zit->last_entry * zh->entrysz + 1];
298  void *this_value = &zh->entries[zit->last_entry * zh->entrysz + 1 + zh->keysz];
299 
300  if (outkey != NULL)
301  *((void**) outkey) = this_key;
302  if (outvalue != NULL)
303  *((void**) outvalue) = this_value;
304 
305  return 1;
306  }
307  }
308 }
309 
310 int zhash_iterator_next(zhash_iterator_t *zit, void *outkey, void *outvalue)
311 {
312  const zhash_t *zh = zit->czh;
313 
314  void *outkeyp, *outvaluep;
315 
316  if (!zhash_iterator_next_volatile(zit, &outkeyp, &outvaluep))
317  return 0;
318 
319  if (outkey != NULL)
320  memcpy(outkey, outkeyp, zh->keysz);
321  if (outvalue != NULL)
322  memcpy(outvalue, outvaluep, zh->valuesz);
323 
324  return 1;
325 }
326 
328 {
329  assert(zit->zh); // can't call _remove on a iterator with const zhash
330  zhash_t *zh = zit->zh;
331 
332  zh->entries[zit->last_entry * zh->entrysz] = 0;
333  zh->size--;
334 
335  // re-insert following entries
336  int entry_idx = (zit->last_entry + 1) & (zh->nentries - 1);
337  while (zh->entries[entry_idx *zh->entrysz]) {
338  // completely remove this entry
339  char *tmp = malloc(sizeof(char)*zh->entrysz);
340  memcpy(tmp, &zh->entries[entry_idx * zh->entrysz], zh->entrysz);
341  zh->entries[entry_idx * zh->entrysz] = 0;
342  zh->size--;
343 
344  // reinsert it
345  if (zhash_put(zh, &tmp[1], &tmp[1+zh->keysz], NULL, NULL))
346  assert(0);
347  free(tmp);
348 
349  entry_idx = (entry_idx + 1) & (zh->nentries - 1);
350  }
351 
352  zit->last_entry--;
353 }
354 
355 void zhash_map_keys(zhash_t *zh, void (*f)(void*))
356 {
357  assert(zh != NULL);
358  if (f == NULL)
359  return;
360 
361  zhash_iterator_t itr;
362  zhash_iterator_init(zh, &itr);
363 
364  void *key, *value;
365 
366  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
367  f(key);
368  }
369 }
370 
371 void zhash_vmap_keys(zhash_t * zh, void (*f)(void*))
372 {
373  assert(zh != NULL);
374  if (f == NULL)
375  return;
376 
377  zhash_iterator_t itr;
378  zhash_iterator_init(zh, &itr);
379 
380  void *key, *value;
381 
382  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
383  void *p = *(void**) key;
384  f(p);
385  }
386 }
387 
388 void zhash_map_values(zhash_t * zh, void (*f)(void*))
389 {
390  assert(zh != NULL);
391  if (f == NULL)
392  return;
393 
394  zhash_iterator_t itr;
395  zhash_iterator_init(zh, &itr);
396 
397  void *key, *value;
398  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
399  f(value);
400  }
401 }
402 
403 void zhash_vmap_values(zhash_t * zh, void (*f)(void*))
404 {
405  assert(zh != NULL);
406  if (f == NULL)
407  return;
408 
409  zhash_iterator_t itr;
410  zhash_iterator_init(zh, &itr);
411 
412  void *key, *value;
413  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
414  void *p = *(void**) value;
415  f(p);
416  }
417 }
418 
420 {
421  assert(zh != NULL);
422 
423  zarray_t *za = zarray_create(zh->keysz);
424 
425  zhash_iterator_t itr;
426  zhash_iterator_init_const(zh, &itr);
427 
428  void *key, *value;
429  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
430  zarray_add(za, key);
431  }
432 
433  return za;
434 }
435 
437 {
438  assert(zh != NULL);
439 
440  zarray_t *za = zarray_create(zh->valuesz);
441 
442  zhash_iterator_t itr;
443  zhash_iterator_init_const(zh, &itr);
444 
445  void *key, *value;
446  while(zhash_iterator_next_volatile(&itr, &key, &value)) {
447  zarray_add(za, value);
448  }
449 
450  return za;
451 }
452 
453 
454 uint32_t zhash_uint32_hash(const void *_a)
455 {
456  assert(_a != NULL);
457 
458  uint32_t a = *((uint32_t*) _a);
459  return a;
460 }
461 
462 int zhash_uint32_equals(const void *_a, const void *_b)
463 {
464  assert(_a != NULL);
465  assert(_b != NULL);
466 
467  uint32_t a = *((uint32_t*) _a);
468  uint32_t b = *((uint32_t*) _b);
469 
470  return a==b;
471 }
472 
473 uint32_t zhash_uint64_hash(const void *_a)
474 {
475  assert(_a != NULL);
476 
477  uint64_t a = *((uint64_t*) _a);
478  return (uint32_t) (a ^ (a >> 32));
479 }
480 
481 int zhash_uint64_equals(const void *_a, const void *_b)
482 {
483  assert(_a != NULL);
484  assert(_b != NULL);
485 
486  uint64_t a = *((uint64_t*) _a);
487  uint64_t b = *((uint64_t*) _b);
488 
489  return a==b;
490 }
491 
492 
494 {
495  const void *p;
496  uint32_t i;
497 };
498 
499 uint32_t zhash_ptr_hash(const void *a)
500 {
501  assert(a != NULL);
502 
503  union uintpointer ip;
504  ip.p = * (void**)a;
505 
506  // compute a hash from the lower 32 bits of the pointer (on LE systems)
507  uint32_t hash = ip.i;
508  hash ^= (hash >> 7);
509 
510  return hash;
511 }
512 
513 
514 int zhash_ptr_equals(const void *a, const void *b)
515 {
516  assert(a != NULL);
517  assert(b != NULL);
518 
519  const void * ptra = * (void**)a;
520  const void * ptrb = * (void**)b;
521  return ptra == ptrb;
522 }
523 
524 
525 int zhash_str_equals(const void *_a, const void *_b)
526 {
527  assert(_a != NULL);
528  assert(_b != NULL);
529 
530  char *a = * (char**)_a;
531  char *b = * (char**)_b;
532 
533  return !strcmp(a, b);
534 }
535 
536 uint32_t zhash_str_hash(const void *_a)
537 {
538  assert(_a != NULL);
539 
540  char *a = * (char**)_a;
541 
542  uint32_t hash = 0;
543  while (*a != 0) {
544  // optimization of hash x FNV_prime
545  hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
546  hash ^= *a;
547  a++;
548  }
549 
550  return hash;
551 }
552 
553 
555 {
556  for (int entry_idx = 0; entry_idx < zh->nentries; entry_idx++) {
557  char *k, *v;
558  memcpy(&k, &zh->entries[entry_idx * zh->entrysz + 1], sizeof(char*));
559  memcpy(&v, &zh->entries[entry_idx * zh->entrysz + 1 + zh->keysz], sizeof(char*));
560  printf("%d: %d, %s => %s\n", entry_idx, zh->entries[entry_idx * zh->entrysz], k, v);
561  }
562 }
zhash_iterator_remove
void zhash_iterator_remove(zhash_iterator_t *zit)
Definition: zhash.c:327
zhash_str_hash
uint32_t zhash_str_hash(const void *_a)
Definition: zhash.c:536
zarray_create
static zarray_t * zarray_create(size_t el_sz)
Definition: zarray.h:57
zhash_uint64_hash
uint32_t zhash_uint64_hash(const void *_a)
Definition: zhash.c:473
zhash_uint32_equals
int zhash_uint32_equals(const void *_a, const void *_b)
Definition: zhash.c:462
zhash_remove
int zhash_remove(zhash_t *zh, const void *key, void *old_key, void *old_value)
Definition: zhash.c:202
uintpointer::p
const void * p
Definition: zhash.c:495
uintpointer
Definition: zhash.c:493
zhash_map_values
void zhash_map_values(zhash_t *zh, void(*f)(void *))
Definition: zhash.c:388
zhash_iterator::last_entry
int last_entry
Definition: zhash.h:63
zhash_create_capacity
zhash_t * zhash_create_capacity(size_t keysz, size_t valuesz, uint32_t(*hash)(const void *a), int(*equals)(const void *a, const void *b), int capacity)
Definition: zhash.c:57
zhash_iterator_init_const
void zhash_iterator_init_const(const zhash_t *zh, zhash_iterator_t *zit)
Definition: zhash.c:279
zhash_iterator::zh
zhash_t * zh
Definition: zhash.h:61
zarray
Definition: zarray.h:43
zhash_iterator_next
int zhash_iterator_next(zhash_iterator_t *zit, void *outkey, void *outvalue)
Definition: zhash.c:310
zhash_size
int zhash_size(const zhash_t *zh)
Definition: zhash.c:106
zhash::nentries
int nentries
Definition: zhash.c:54
zhash::valuesz
size_t valuesz
Definition: zhash.c:43
zhash::equals
int(* equals)(const void *a, const void *b)
Definition: zhash.c:49
zhash::hash
uint32_t(* hash)(const void *a)
Definition: zhash.c:46
zhash_create
zhash_t * zhash_create(size_t keysz, size_t valuesz, uint32_t(*hash)(const void *a), int(*equals)(const void *a, const void *b))
Definition: zhash.c:91
zhash::keysz
size_t keysz
Definition: zhash.c:43
zhash_put
int zhash_put(zhash_t *zh, const void *key, const void *value, void *oldkey, void *oldvalue)
Definition: zhash.c:146
zhash_ptr_equals
int zhash_ptr_equals(const void *a, const void *b)
Definition: zhash.c:514
zhash_debug
void zhash_debug(zhash_t *zh)
Definition: zhash.c:554
zhash_iterator::czh
const zhash_t * czh
Definition: zhash.h:62
zhash_get_volatile
int zhash_get_volatile(const zhash_t *zh, const void *key, void *out_value)
Definition: zhash.c:117
zhash_iterator_next_volatile
int zhash_iterator_next_volatile(zhash_iterator_t *zit, void *outkey, void *outvalue)
Definition: zhash.c:286
zhash_map_keys
void zhash_map_keys(zhash_t *zh, void(*f)(void *))
Definition: zhash.c:355
zhash_vmap_keys
void zhash_vmap_keys(zhash_t *zh, void(*f)(void *))
Definition: zhash.c:371
zhash.h
zhash_vmap_values
void zhash_vmap_values(zhash_t *zh, void(*f)(void *))
Definition: zhash.c:403
zhash_uint64_equals
int zhash_uint64_equals(const void *_a, const void *_b)
Definition: zhash.c:481
zhash_str_equals
int zhash_str_equals(const void *_a, const void *_b)
Definition: zhash.c:525
zhash
Definition: zhash.c:41
zhash_values
zarray_t * zhash_values(const zhash_t *zh)
Definition: zhash.c:436
zhash::size
int size
Definition: zhash.c:51
zarray_add
static void zarray_add(zarray_t *za, const void *p)
Definition: zarray.h:179
zhash_copy
zhash_t * zhash_copy(const zhash_t *zh)
Definition: zhash.c:248
zhash::entrysz
int entrysz
Definition: zhash.c:44
zhash_destroy
void zhash_destroy(zhash_t *zh)
Definition: zhash.c:97
ZHASH_FACTOR_REALLOC
#define ZHASH_FACTOR_REALLOC
Definition: zhash.c:39
uintpointer::i
uint32_t i
Definition: zhash.c:496
zhash_keys
zarray_t * zhash_keys(const zhash_t *zh)
Definition: zhash.c:419
ZHASH_FACTOR_CRITICAL
#define ZHASH_FACTOR_CRITICAL
Definition: zhash.c:36
zhash::entries
char * entries
Definition: zhash.c:53
zhash_clear
void zhash_clear(zhash_t *zh)
Definition: zhash.c:111
zhash_iterator_init
void zhash_iterator_init(zhash_t *zh, zhash_iterator_t *zit)
Definition: zhash.c:272
zhash_ptr_hash
uint32_t zhash_ptr_hash(const void *a)
Definition: zhash.c:499
zhash_uint32_hash
uint32_t zhash_uint32_hash(const void *_a)
Definition: zhash.c:454
zhash_contains
int zhash_contains(const zhash_t *zh, const void *key)
Definition: zhash.c:266
zhash_iterator
Definition: zhash.h:59
zhash_get
int zhash_get(const zhash_t *zh, const void *key, void *out_value)
Definition: zhash.c:135


apriltag
Author(s): Edwin Olson , Max Krogius
autogenerated on Sun Apr 20 2025 02:08:47