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


apriltags2
Author(s): Danylo Malyuta
autogenerated on Fri Oct 19 2018 04:02:32