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 
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)())
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)())
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)())
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)())
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 }
int size
Definition: zhash.c:51
int entrysz
Definition: zhash.c:44
int(* equals)(const void *a, const void *b)
Definition: zhash.c:49
const void * p
Definition: zhash.c:495
void zhash_map_keys(zhash_t *zh, void(*f)())
Definition: zhash.c:355
uint32_t zhash_uint32_hash(const void *_a)
Definition: zhash.c:454
int zhash_get(const zhash_t *zh, const void *key, void *out_value)
Definition: zhash.c:135
#define ZHASH_FACTOR_REALLOC
Definition: zhash.c:39
uint32_t zhash_str_hash(const void *_a)
Definition: zhash.c:536
int last_entry
Definition: zhash.h:63
char * entries
Definition: zhash.c:53
uint32_t zhash_uint64_hash(const void *_a)
Definition: zhash.c:473
int zhash_iterator_next(zhash_iterator_t *zit, void *outkey, void *outvalue)
Definition: zhash.c:310
int zhash_put(zhash_t *zh, const void *key, const void *value, void *oldkey, void *oldvalue)
Definition: zhash.c:146
int zhash_iterator_next_volatile(zhash_iterator_t *zit, void *outkey, void *outvalue)
Definition: zhash.c:286
uint32_t(* hash)(const void *a)
Definition: zhash.c:46
zhash_t * zh
Definition: zhash.h:61
Definition: zhash.c:41
void zhash_map_values(zhash_t *zh, void(*f)())
Definition: zhash.c:388
size_t keysz
Definition: zhash.c:43
void zhash_vmap_values(zhash_t *zh, void(*f)())
Definition: zhash.c:403
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
int zhash_uint32_equals(const void *_a, const void *_b)
Definition: zhash.c:462
static zarray_t * zarray_create(size_t el_sz)
Definition: zarray.h:57
int nentries
Definition: zhash.c:54
const zhash_t * czh
Definition: zhash.h:62
size_t valuesz
Definition: zhash.c:43
int zhash_uint64_equals(const void *_a, const void *_b)
Definition: zhash.c:481
#define ZHASH_FACTOR_CRITICAL
Definition: zhash.c:36
void zhash_clear(zhash_t *zh)
Definition: zhash.c:111
void zhash_iterator_init(zhash_t *zh, zhash_iterator_t *zit)
Definition: zhash.c:272
void zhash_iterator_init_const(const zhash_t *zh, zhash_iterator_t *zit)
Definition: zhash.c:279
zhash_t * zhash_copy(const zhash_t *zh)
Definition: zhash.c:248
int zhash_size(const zhash_t *zh)
Definition: zhash.c:106
void zhash_vmap_keys(zhash_t *zh, void(*f)())
Definition: zhash.c:371
int zhash_contains(const zhash_t *zh, const void *key)
Definition: zhash.c:266
Definition: zarray.h:43
void zhash_destroy(zhash_t *zh)
Definition: zhash.c:97
zarray_t * zhash_keys(const zhash_t *zh)
Definition: zhash.c:419
int zhash_remove(zhash_t *zh, const void *key, void *old_key, void *old_value)
Definition: zhash.c:202
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
int zhash_ptr_equals(const void *a, const void *b)
Definition: zhash.c:514
void zhash_debug(zhash_t *zh)
Definition: zhash.c:554
zarray_t * zhash_values(const zhash_t *zh)
Definition: zhash.c:436
int zhash_get_volatile(const zhash_t *zh, const void *key, void *out_value)
Definition: zhash.c:117
uint32_t i
Definition: zhash.c:496
void zhash_iterator_remove(zhash_iterator_t *zit)
Definition: zhash.c:327
int zhash_str_equals(const void *_a, const void *_b)
Definition: zhash.c:525
static void zarray_add(zarray_t *za, const void *p)
Definition: zarray.h:179
uint32_t zhash_ptr_hash(const void *a)
Definition: zhash.c:499


apriltag
Author(s): Edwin Olson , Max Krogius
autogenerated on Mon Jun 26 2023 02:26:35