2 * originally by gtsouk@cslab.ece.ntua.gr
3 * -- kkourt@cslab.ece.ntua.gr
6 #include <xtypes/xhash.h>
8 #define UNUSED (~(xhashidx)0) /* this entry was never used */
9 #define DUMMY ((~(xhashidx)0)-1) /* this entry was used, but now its empty */
11 //#define VAL_OVERLOAD
12 //#define KEY_OVERLOAD
13 //#define NO_OVERLOAD /* use separate bitarray -- not implemented */
15 #define PERTURB_SHIFT 5
18 set_dummy_key(xhash_t *xhash, xhashidx idx)
20 xhashidx *kvs = xhash_kvs(xhash);
25 set_dummy_val(xhash_t *xhash, xhashidx idx)
27 xhashidx *vals = xhash_vals(xhash);
32 item_dummy(xhash_t *xhash, xhashidx idx, bool vals)
36 xhashidx *kvs = xhash_kvs(xhash);
39 ret = (kvs[idx] == DUMMY);
41 #if defined(VAL_OVERLOAD)
42 pvals = xhash_vals(xhash);
43 ret = (pvals[idx] == DUMMY);
44 #elif defined(KEY_OVERLOAD)
45 ret = (kvs[idx] == DUMMY);
52 static void set_dummy_item(xhash_t *xhash, xhashidx idx, bool vals)
55 set_dummy_key(xhash, idx);
60 set_dummy_val(xhash, idx);
62 #elif defined(KEY_OVERLOAD)
63 set_dummy_key(xhash, idx);
68 set_unused_key(xhash_t *xhash, xhashidx idx)
70 xhashidx *kvs = xhash_kvs(xhash);
75 set_unused_val(xhash_t *xhash, xhashidx idx)
77 xhashidx *vals = xhash_vals(xhash);
82 val_unused(xhash_t *xhash, xhashidx idx)
84 xhashidx *vals = xhash_vals(xhash);
85 return vals[idx] == UNUSED;
89 item_unused(xhash_t *xhash, xhashidx idx, bool vals)
91 xhashidx *kvs = xhash_kvs(xhash);
93 return kvs[idx] == UNUSED;
96 #if defined(VAL_OVERLOAD)
97 return val_unused(xhash, idx);
98 #elif defined(KEY_OVERLOAD)
99 return kvs[idx] == UNUSED;
104 static inline unsigned item_valid(xhash_t *xhash, xhashidx idx, bool vals)
106 return !(item_dummy(xhash, idx, vals) || item_unused(xhash, idx, vals));
109 static void __attribute__((unused))
110 assert_key(xhashidx key)
112 assert((key != UNUSED) && (key != DUMMY));
116 assert_val(xhashidx val)
118 assert((val != UNUSED) && (val != DUMMY));
122 assert_kv(xhashidx k, xhashidx v)
124 #if defined(KEY_OVERLOAD)
126 #elif defined(VAL_OVERLOAD)
133 xhash_init__(xhash_t *xhash, xhashidx size_shift, xhashidx minsize_shift,
134 enum xhash_type type, bool vals)
136 xhashidx nr_items = 1UL << size_shift;
137 xhashidx *kvs = (xhashidx *) ((char *) xhash + sizeof(struct xhash));
140 XPTRSET(&xhash->kvs, kvs);
144 for (i=0; i < nr_items; i++)
149 for (i=0; i < nr_items; i++){
150 #if defined(VAL_OVERLOAD)
151 kvs[nr_items + i] = UNUSED;
152 #elif defined(KEY_OVERLOAD)
158 xhash->dummies = xhash->used = 0;
159 xhash->size_shift = size_shift;
160 xhash->minsize_shift = minsize_shift;
163 ZEROSTAT(xhash->inserts);
164 ZEROSTAT(xhash->deletes);
165 ZEROSTAT(xhash->lookups);
166 ZEROSTAT(xhash->bounces);
170 get_alloc_size(xhashidx size_shift, bool vals)
172 xhashidx nr_items = 1UL << size_shift;
173 size_t keys_size = nr_items*sizeof(xhashidx);
174 size_t alloc_size = vals ? keys_size<<1 : keys_size;
175 return sizeof(struct xhash) + alloc_size;
180 xhash_new__(xhashidx size_shift, xhashidx minsize_shift,
181 enum xhash_type type, bool vals)
184 xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
186 XSEGLOG("couldn't malloc\n");
190 xhash_init__(xhash, size_shift, minsize_shift, type, vals);
197 xhash_resize__(struct xhash *xhash, xhashidx new_size_shift, bool vals)
199 return xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, vals);
203 xhash_delete__(xhash_t *xhash, xhashidx key, bool vals)
205 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
206 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
207 xhashidx perturb = key;
208 xhashidx mask = xhash_size(xhash)-1;
209 xhashidx idx = hash_fun(key) & mask;
210 xhashidx *kvs = xhash_kvs(xhash);
213 if ( item_unused(xhash, idx, vals) ){
217 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
218 INCSTAT(xhash->deletes);
219 set_dummy_item(xhash, idx, vals);
221 //fprintf(stderr, "rm: used: %lu\n", xhash->used);
226 INCSTAT(xhash->bounces);
227 idx = ((idx<<2) + idx + 1 + perturb) & mask;
228 perturb >>= PERTURB_SHIFT;
233 xhash_grow_size_shift(xhash_t *xhash)
235 xhashidx old_size_shift = xhash->size_shift;
236 xhashidx new_size_shift;
240 //printf("used: %lu\n", u);
241 if (u/2 + u >= ((xhashidx)1 << old_size_shift)) {
242 new_size_shift = old_size_shift + 1;
244 new_size_shift = old_size_shift;
247 return new_size_shift;
251 xhash_shrink_size_shift(xhash_t *xhash)
253 xhashidx old_size_shift = xhash->size_shift;
254 xhashidx new_size_shift;
255 new_size_shift = old_size_shift - 1;
256 if (new_size_shift < xhash->minsize_shift) {
257 new_size_shift = xhash->minsize_shift;
259 return new_size_shift;
263 grow_check(xhash_t *xhash)
265 xhashidx size_shift = xhash->size_shift;
266 xhashidx u = xhash->used + xhash->dummies;
267 xhashidx size = (xhashidx)1UL<<size_shift;
268 return ((u/2 + u) >= size) ? true : false;
272 shrink_check(xhash_t *xhash)
274 xhashidx size_shift = xhash->size_shift;
275 xhashidx size = (xhashidx)1<<size_shift;
276 xhashidx u = xhash->used;
277 return (4*u < size && size_shift > xhash->minsize_shift) ? true : false;
286 xhash_get_alloc_size(xhashidx size_shift)
288 return get_alloc_size(size_shift, true);
292 xhash_new(xhashidx minsize_shift, enum xhash_type type)
294 return xhash_new__(minsize_shift, minsize_shift, type, true);
297 void xhash_free(struct xhash *xhash)
302 void xhash_init(struct xhash *xhash, xhashidx minsize_shift, enum xhash_type type)
304 xhash_init__(xhash, minsize_shift, minsize_shift, type, true);
309 xhash_grow(struct xhash *xhash)
311 xhashidx new_size_shift = xhash_grow_size_shift(xhash);
312 return xhash_resize(xhash, new_size_shift);
316 xhash_shrink(struct xhash *xhash)
318 xhashidx new_size_shift = xhash_shrink_size_shift(xhash);
319 return xhash_resize(xhash, new_size_shift);
322 static inline xhash_t*
323 xhash_grow_check(xhash_t *xhash)
325 if (grow_check(xhash))
326 return xhash_grow(xhash);
332 #define PHASH_UPDATE(xhash, key, val, vals_flag) \
334 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun; \
335 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun; \
336 xhashidx size = 1UL<<(xhash->size_shift); \
337 xhashidx perturb = key; \
338 xhashidx mask = size-1; \
339 xhashidx idx = hash_fun(key) & mask; \
340 xhashidx *kvs = xhash_kvs(xhash); \
342 INCSTAT(xhash->inserts); \
344 if ( !item_valid(xhash, idx, vals_flag) ){ \
345 PHUPD_SET__(xhash, idx, key, val); \
348 if (cmp_fun(kvs[idx], key)){ \
349 PHUPD_UPDATE__(xhash, idx, key, val); \
353 again: __attribute__((unused)) \
354 INCSTAT(xhash->bounces); \
355 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
356 perturb >>= PERTURB_SHIFT; \
361 set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
363 xhashidx *kvs = xhash_kvs(p);
364 xhashidx *vals = xhash_vals(p);
369 void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
371 xhashidx *kvs = xhash_kvs(p);
372 xhashidx *vals = xhash_vals(p);
373 if (item_dummy(p, idx, true))
381 inc_val(xhash_t *p, xhashidx idx, xhashidx val)
383 xhashidx *vals = xhash_vals(p);
387 void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
389 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
390 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
391 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
392 PHASH_UPDATE(xhash, key, val, true)
393 #undef PHUPD_UPDATE__
397 int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
399 if (grow_check(xhash))
400 return -XHASH_ERESIZE;
401 xhash_insert__(xhash, key, val);
406 void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
408 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
409 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
410 PHASH_UPDATE(xhash, key, val, true)
411 #undef PHUPD_UPDATE__
415 int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
417 if (grow_check(xhash))
418 return -XHASH_ERESIZE;
419 xhash_freql_update__(xhash, key, val);
424 xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhash_t *new)
429 new = xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, true);
431 xhash_init__(new, new_size_shift, xhash->minsize_shift, xhash->type, true);
436 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
437 for (i = 0; i < xhash_size(xhash); i++) {
438 if (item_valid(xhash, i, true)){
439 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
440 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
450 * note that his function does not modify the internal structure of the hash
451 * and thus its safe to use it for updating values during a xhash_iterate()
453 int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
455 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
456 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
457 #define PHUPD_SET__(_p, _i, _k, _v) goto again
458 PHASH_UPDATE(xhash, key, val, true)
459 #undef PHUPD_UPDATE__
466 int xhash_delete(struct xhash *xhash, xhashidx key)
468 if (shrink_check(xhash))
469 return -XHASH_ERESIZE;
470 return xhash_delete__(xhash, key, true);
473 int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
475 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
476 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
477 xhashidx size_shift = xhash->size_shift;
478 xhashidx size = (xhashidx)1<<size_shift;
479 xhashidx perturb = key;
480 xhashidx mask = size-1;
481 xhashidx idx = hash_fun(key) & mask;
482 xhashidx *kvs = xhash_kvs(xhash);
484 INCSTAT(xhash->lookups);
486 if ( item_unused(xhash, idx, vals) )
487 return -XHASH_EEXIST;
489 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
494 INCSTAT(xhash->bounces);
495 idx = ((idx<<2) + idx + 1 + perturb) & mask;
496 perturb >>= PERTURB_SHIFT;
500 int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
503 int ret = xhash_lookup__(xhash, key, &idx, true);
505 xhashidx *values = xhash_vals(xhash);
511 //FIXME iteration broken
513 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
515 pi->cnt = pi->loc = 0;
519 xhash_iterate__(xhash_t *xhash, bool vals,
520 xhash_iter_t *pi, xhashidx *key_ret, xhashidx *idx_ret)
522 xhashidx idx = pi->loc;
523 xhashidx size = (xhashidx)1<<xhash->size_shift;
524 xhashidx *kvs = xhash_kvs(xhash);
525 INCSTAT(xhash->lookups);
527 if (xhash->used == pi->cnt || idx >= size)
530 if (item_valid(xhash, idx, vals)){
542 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
545 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
547 xhashidx *vals = xhash_vals(xhash);
553 void xhash_print(xhash_t *xhash)
559 xhash_iter_init(xhash, &pi);
560 XSEGLOG("PHASH(%p):\n", xhash);
562 ret = xhash_iterate(xhash, &pi, &key, &val);
566 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
576 " insert : I <key> <val> \n"
577 " update : U <key> <val> (->v += val if exists) \n"
579 " delete : D <key> \n"
584 int main(int argc, char **argv)
587 char *s, buf[BUFLEN];
591 ph = xhash_new(2, INTEGER);
594 s = fgets(buf, BUFLEN-1, stdin);
601 ret = sscanf(s+1, "%lu %lu", &key, &val);
603 xhash_insert(ph, key, val);
608 ret = sscanf(s+1, "%lu %lu", &key, &val);
610 xhash_freql_update(ph, key, val);
615 ret = sscanf(s+1, "%lu", &key);
617 ret = xhash_lookup(ph, key, &val);
619 printf("%lu\n", val);
627 ret = sscanf(s+1, "%lu", &key);
629 xhash_delete(ph, key);
634 printf("%lu\n", xhash_elements(ph));
662 pset_new(xhashidx minsize_shift)
665 pset = malloc(sizeof(pset_t));
670 xhash_init__(&pset->ph_, minsize_shift, false);
675 pset_init(pset_t *pset, xhashidx minsize_shift)
677 xhash_init__(&pset->ph_, minsize_shift, false);
681 pset_free(pset_t *pset)
683 xhash_tfree(&pset->ph_);
688 pset_tfree(pset_t *pset)
690 xhash_tfree(&pset->ph_);
694 pset_resize(pset_t *pset, xhashidx new_size_shift)
697 xhash_cp(&(old.ph_), &pset->ph_);
699 xhash_resize__(&pset->ph_, new_size_shift, false);
700 for (xhashidx i = 0; i < pset_size(&old); i++) {
701 if (item_valid(&(old.ph_), i, false)){
702 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
703 pset_insert(pset, old.ph_.kvs[i]);
710 pset_grow(pset_t *pset)
712 xhashidx new_size_shift = grow_size_shift(&pset->ph_);
713 pset_resize(pset, new_size_shift);
717 pset_grow_check(pset_t *pset)
719 if (grow_check(&pset->ph_))
723 void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
725 if (item_dummy(p, idx, false))
731 void pset_insert(pset_t *pset, xhashidx key)
733 xhash_t *ph = &pset->ph_;
735 pset_grow_check(pset);
736 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
737 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
738 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
739 #undef PHUPD_UPDATE__
744 pset_shrink(pset_t *pset)
746 xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
747 pset_resize(pset, new_size_shift);
750 int pset_delete(pset_t *pset, xhashidx key)
752 if (pset->ph_.used == 0)
756 xhashidx size_shift = pset->ph_.size_shift;
757 xhashidx size = (xhashidx)1<<size_shift;
758 xhashidx u = pset->ph_.used;
761 return xhash_delete__(&pset->ph_, key, false);
764 bool pset_lookup(pset_t *pset, xhashidx key)
767 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
770 int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
773 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
777 void pset_print(pset_t *pset)
783 pset_iter_init(pset, &pi);
784 printf("PSET(%p):\n", pset);
786 ret = pset_iterate(pset, &pi, &key);
790 printf(" 0x%017lx\n", key);
795 #if defined(PSET_MAIN)
800 " insert : I <key> <val> \n"
802 " delete : D <key> \n"
807 int main(int argc, char **argv)
810 char *s, buf[BUFLEN];
817 s = fgets(buf, BUFLEN-1, stdin);
824 ret = sscanf(s+1, "%lu", &key);
826 pset_insert(ps, key);
831 ret = sscanf(s+1, "%lu", &key);
833 ret = pset_lookup(ps, key);
834 printf("%lu -> %s\n", key, ret ? "true" : "false");
839 ret = sscanf(s+1, "%lu", &key);
841 pset_delete(ps, key);
846 printf("%lu\n", pset_elements(ps));
870 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4