10 * originally by gtsouk@cslab.ece.ntua.gr
11 * -- kkourt@cslab.ece.ntua.gr
14 #include <xtypes/xhash.h>
16 #define UNUSED (~(ul_t)0) /* this entry was never used */
17 #define DUMMY ((~(ul_t)0)-1) /* this entry was used, but now its empty */
19 //#define VAL_OVERLOAD
20 //#define KEY_OVERLOAD
21 //#define NO_OVERLOAD /* use separate bitarray -- not implemented */
23 #define PERTURB_SHIFT 5
26 set_dummy_key(xhash_t *xhash, ul_t idx)
28 ul_t *kvs = xhash_kvs(xhash);
33 set_dummy_val(xhash_t *xhash, ul_t idx)
35 ul_t *vals = xhash_vals(xhash);
40 item_dummy(xhash_t *xhash, ul_t idx, bool vals)
44 ul_t *kvs = xhash_kvs(xhash);
47 ret = (kvs[idx] == DUMMY);
49 #if defined(VAL_OVERLOAD)
51 pvals = xhash_vals(xhash);
52 ret = (pvals[idx] == DUMMY);
53 #elif defined(KEY_OVERLOAD)
54 ret = (kvs[idx] == DUMMY);
61 static void set_dummy_item(xhash_t *xhash, ul_t idx, bool vals)
64 set_dummy_key(xhash, idx);
70 set_dummy_val(xhash, idx);
72 #elif defined(KEY_OVERLOAD)
73 set_dummy_key(xhash, idx);
78 set_unused_key(xhash_t *xhash, ul_t idx)
80 ul_t *kvs = xhash_kvs(xhash);
85 set_unused_val(xhash_t *xhash, ul_t idx)
87 ul_t *vals = xhash_vals(xhash);
92 val_unused(xhash_t *xhash, ul_t idx)
94 ul_t *vals = xhash_vals(xhash);
95 return vals[idx] == UNUSED;
99 item_unused(xhash_t *xhash, ul_t idx, bool vals)
101 ul_t *kvs = xhash_kvs(xhash);
103 return kvs[idx] == UNUSED;
106 #if defined(VAL_OVERLOAD)
108 return val_unused(xhash, idx);
109 #elif defined(KEY_OVERLOAD)
110 return kvs[idx] == UNUSED;
115 static inline unsigned item_valid(xhash_t *xhash, ul_t idx, bool vals)
117 return !(item_dummy(xhash, idx, vals) || item_unused(xhash, idx, vals));
120 static void __attribute__((unused))
123 assert((key != UNUSED) && (key != DUMMY));
129 assert((val != UNUSED) && (val != DUMMY));
133 assert_kv(ul_t k, ul_t v)
135 #if defined(KEY_OVERLOAD)
137 #elif defined(VAL_OVERLOAD)
143 xhash_init__(xhash_t *xhash, ul_t size_shift, ul_t minsize_shift, bool vals)
145 ul_t nr_items = 1UL << size_shift;
146 ul_t *kvs = (ul_t *) ((char *) xhash + sizeof(struct xhash));
149 XPTRSET(&xhash->kvs, kvs);
153 for (i=0; i < nr_items; i++)
158 for (i=0; i < nr_items; i++){
159 #if defined(VAL_OVERLOAD)
161 kvs[nr_items + i] = UNUSED;
162 #elif defined(KEY_OVERLOAD)
168 xhash->dummies = xhash->used = 0;
169 xhash->size_shift = size_shift;
170 xhash->minsize_shift = minsize_shift;
172 ZEROSTAT(xhash->inserts);
173 ZEROSTAT(xhash->deletes);
174 ZEROSTAT(xhash->lookups);
175 ZEROSTAT(xhash->bounces);
179 get_alloc_size(ul_t size_shift, bool vals)
181 ul_t nr_items = 1UL << size_shift;
182 size_t keys_size = nr_items*sizeof(ul_t);
183 size_t alloc_size = vals ? keys_size<<1 : keys_size;
184 return sizeof(struct xhash) + alloc_size;
189 xhash_new__(ul_t size_shift, ul_t minsize_shift, bool vals) {
191 xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
193 XSEGLOG("couldn't malloc\n");
197 xhash_init__(xhash, size_shift, minsize_shift, vals);
204 xhash_resize__(struct xhash *xhash, ul_t new_size_shift, bool vals)
206 return xhash_new__(new_size_shift, xhash->minsize_shift, vals);
210 xhash_delete__(xhash_t *xhash, ul_t key, bool vals)
213 ul_t mask = xhash_size(xhash)-1;
214 ul_t idx = key & mask;
215 ul_t *kvs = xhash_kvs(xhash);
218 if ( item_unused(xhash, idx, vals) ){
223 if ( !item_dummy(xhash, idx, vals) && kvs[idx] == key){
224 INCSTAT(xhash->deletes);
225 set_dummy_item(xhash, idx, vals);
227 //fprintf(stderr, "rm: used: %lu\n", xhash->used);
232 INCSTAT(xhash->bounces);
233 idx = ((idx<<2) + idx + 1 + perturb) & mask;
234 perturb >>= PERTURB_SHIFT;
239 grow_size_shift(xhash_t *xhash)
241 ul_t old_size_shift = xhash->size_shift;
246 //printf("used: %lu\n", u);
247 if (u/2 + u >= ((ul_t)1 << old_size_shift)) {
248 new_size_shift = old_size_shift + 1;
250 new_size_shift = old_size_shift;
253 return new_size_shift;
257 shrink_size_shift(xhash_t *xhash)
259 ul_t old_size_shift = xhash->size_shift;
261 new_size_shift = old_size_shift - 1;
262 if (new_size_shift < xhash->minsize_shift) {
263 new_size_shift = xhash->minsize_shift;
265 return new_size_shift;
269 grow_check(xhash_t *xhash)
271 ul_t size_shift = xhash->size_shift;
272 ul_t u = xhash->used + xhash->dummies;
273 ul_t size = (ul_t)1UL<<size_shift;
274 return ((u/2 + u) >= size) ? true : false;
278 shrink_check(xhash_t *xhash)
280 ul_t size_shift = xhash->size_shift;
281 ul_t size = (ul_t)1<<size_shift;
282 ul_t u = xhash->used;
283 return (4*u < size && size_shift >= xhash->minsize_shift) ? true : false;
292 xhash_get_alloc_size(ul_t size_shift)
294 return get_alloc_size(size_shift, true);
298 xhash_new(ul_t minsize_shift)
300 return xhash_new__(minsize_shift, minsize_shift, true);
303 void xhash_free(struct xhash *xhash)
308 void xhash_init(struct xhash *xhash, ul_t minsize_shift)
310 xhash_init__(xhash, minsize_shift, minsize_shift, true);
315 xhash_grow(struct xhash *xhash)
317 ul_t new_size_shift = grow_size_shift(xhash);
318 return xhash_resize(xhash, new_size_shift);
322 xhash_shrink(struct xhash *xhash)
324 ul_t new_size_shift = shrink_size_shift(xhash);
325 return xhash_resize(xhash, new_size_shift);
328 static inline xhash_t*
329 xhash_grow_check(xhash_t *xhash)
331 if (grow_check(xhash))
332 return xhash_grow(xhash);
338 #define PHASH_UPDATE(xhash, key, val, vals_flag) \
340 ul_t size = 1UL<<(xhash->size_shift); \
341 ul_t perturb = key; \
342 ul_t mask = size-1; \
343 ul_t idx = key & mask; \
344 ul_t *kvs = xhash_kvs(xhash); \
346 INCSTAT(xhash->inserts); \
348 if ( !item_valid(xhash, idx, vals_flag) ){ \
349 PHUPD_SET__(xhash, idx, key, val); \
352 if (kvs[idx] == key){ \
353 PHUPD_UPDATE__(xhash, idx, key, val); \
357 again: __attribute__((unused)) \
358 INCSTAT(xhash->bounces); \
359 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
360 perturb >>= PERTURB_SHIFT; \
365 set_val(xhash_t *p, ul_t idx, ul_t key, ul_t val)
367 ul_t *kvs = xhash_kvs(p);
368 ul_t *vals = xhash_vals(p);
373 void static inline xhash_upd_set(xhash_t *p, ul_t idx, ul_t key, ul_t val)
375 ul_t *kvs = xhash_kvs(p);
376 ul_t *vals = xhash_vals(p);
377 if (item_dummy(p, idx, true))
385 inc_val(xhash_t *p, ul_t idx, ul_t val)
387 ul_t *vals = xhash_vals(p);
391 void xhash_insert__(struct xhash *xhash, ul_t key, ul_t val)
393 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
395 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
396 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
397 PHASH_UPDATE(xhash, key, val, true)
398 #undef PHUPD_UPDATE__
402 int xhash_insert(struct xhash *xhash, ul_t key, ul_t val)
404 if (grow_check(xhash))
405 return -XHASH_ERESIZE;
406 xhash_insert__(xhash, key, val);
411 void xhash_freql_update__(struct xhash *xhash, ul_t key, ul_t val)
415 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
416 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
417 PHASH_UPDATE(xhash, key, val, true)
418 #undef PHUPD_UPDATE__
422 int xhash_freql_update(struct xhash *xhash, ul_t key, ul_t val)
426 if (grow_check(xhash))
427 return -XHASH_ERESIZE;
428 xhash_freql_update__(xhash, key, val);
433 xhash_resize(xhash_t *xhash, ul_t new_size_shift, xhash_t *new)
438 new = xhash_new__(new_size_shift, xhash->minsize_shift, true);
440 xhash_init__(new, new_size_shift, xhash->minsize_shift, true);
442 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
443 for (i = 0; i < xhash_size(xhash); i++) {
444 if (item_valid(xhash, i, true)){
445 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
446 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
456 * note that his function does not modify the internal structure of the hash
457 * and thus its safe to use it for updating values during a xhash_iterate()
459 int xhash_update(struct xhash *xhash, ul_t key, ul_t val) {
461 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
463 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
464 #define PHUPD_SET__(_p, _i, _k, _v) goto again
465 PHASH_UPDATE(xhash, key, val, true)
466 #undef PHUPD_UPDATE__
473 int xhash_delete(struct xhash *xhash, ul_t key)
475 #if defined(KEY_OVERLOAD)
478 if (shrink_check(xhash))
479 return -XHASH_ERESIZE;
480 return xhash_delete__(xhash, key, true);
483 int xhash_lookup__(xhash_t *xhash, ul_t key, ul_t *idx_ret, bool vals)
485 #if defined(KEY_OVERLOAD)
489 ul_t size_shift = xhash->size_shift;
490 ul_t size = (ul_t)1<<size_shift;
493 ul_t idx = key & mask;
494 ul_t *kvs = xhash_kvs(xhash);
496 INCSTAT(xhash->lookups);
498 if ( item_unused(xhash, idx, vals) )
499 return -XHASH_EEXIST;
501 if ( !item_dummy(xhash, idx, vals) && kvs[idx] == key){
506 INCSTAT(xhash->bounces);
507 idx = ((idx<<2) + idx + 1 + perturb) & mask;
508 perturb >>= PERTURB_SHIFT;
512 int xhash_lookup(struct xhash *xhash, ul_t key, ul_t *val)
515 int ret = xhash_lookup__(xhash, key, &idx, true);
517 ul_t *values = xhash_vals(xhash);
524 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
526 pi->cnt = pi->loc = 0;
530 xhash_iterate__(xhash_t *xhash, bool vals,
531 xhash_iter_t *pi, ul_t *key_ret, ul_t *idx_ret)
534 ul_t size = (ul_t)1<<xhash->size_shift;
535 ul_t *kvs = xhash_kvs(xhash);
536 INCSTAT(xhash->lookups);
538 if (xhash->used == pi->cnt || idx >= size)
541 if (item_valid(xhash, idx, vals)){
553 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, ul_t *key, ul_t *val)
556 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
558 ul_t *vals = xhash_vals(xhash);
564 void xhash_print(xhash_t *xhash)
570 xhash_iter_init(xhash, &pi);
571 XSEGLOG("PHASH(%p):\n", xhash);
573 ret = xhash_iterate(xhash, &pi, &key, &val);
577 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
587 " insert : I <key> <val> \n"
588 " update : U <key> <val> (->v += val if exists) \n"
590 " delete : D <key> \n"
595 int main(int argc, char **argv)
598 char *s, buf[BUFLEN];
605 s = fgets(buf, BUFLEN-1, stdin);
612 ret = sscanf(s+1, "%lu %lu", &key, &val);
614 xhash_insert(ph, key, val);
619 ret = sscanf(s+1, "%lu %lu", &key, &val);
621 xhash_freql_update(ph, key, val);
626 ret = sscanf(s+1, "%lu", &key);
628 ret = xhash_lookup(ph, key, &val);
630 printf("%lu\n", val);
638 ret = sscanf(s+1, "%lu", &key);
640 xhash_delete(ph, key);
645 printf("%lu\n", xhash_elements(ph));
673 pset_new(ul_t minsize_shift)
676 pset = malloc(sizeof(pset_t));
681 xhash_init__(&pset->ph_, minsize_shift, false);
686 pset_init(pset_t *pset, ul_t minsize_shift)
688 xhash_init__(&pset->ph_, minsize_shift, false);
692 pset_free(pset_t *pset)
694 xhash_tfree(&pset->ph_);
699 pset_tfree(pset_t *pset)
701 xhash_tfree(&pset->ph_);
705 pset_resize(pset_t *pset, ul_t new_size_shift)
708 xhash_cp(&(old.ph_), &pset->ph_);
710 xhash_resize__(&pset->ph_, new_size_shift, false);
711 for (ul_t i = 0; i < pset_size(&old); i++) {
712 if (item_valid(&(old.ph_), i, false)){
713 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
714 pset_insert(pset, old.ph_.kvs[i]);
721 pset_grow(pset_t *pset)
723 ul_t new_size_shift = grow_size_shift(&pset->ph_);
724 pset_resize(pset, new_size_shift);
728 pset_grow_check(pset_t *pset)
730 if (grow_check(&pset->ph_))
734 void static inline pset_upd_set(xhash_t *p, ul_t idx, ul_t key)
736 if (item_dummy(p, idx, false))
742 void pset_insert(pset_t *pset, ul_t key)
744 xhash_t *ph = &pset->ph_;
746 pset_grow_check(pset);
747 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
748 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
749 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
750 #undef PHUPD_UPDATE__
755 pset_shrink(pset_t *pset)
757 ul_t new_size_shift = shrink_size_shift(&pset->ph_);
758 pset_resize(pset, new_size_shift);
761 int pset_delete(pset_t *pset, ul_t key)
763 if (pset->ph_.used == 0)
767 ul_t size_shift = pset->ph_.size_shift;
768 ul_t size = (ul_t)1<<size_shift;
769 ul_t u = pset->ph_.used;
772 return xhash_delete__(&pset->ph_, key, false);
775 bool pset_lookup(pset_t *pset, ul_t key)
778 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
781 int pset_iterate(pset_t *pset, xhash_iter_t *pi, ul_t *key)
784 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
788 void pset_print(pset_t *pset)
794 pset_iter_init(pset, &pi);
795 printf("PSET(%p):\n", pset);
797 ret = pset_iterate(pset, &pi, &key);
801 printf(" 0x%017lx\n", key);
806 #if defined(PSET_MAIN)
811 " insert : I <key> <val> \n"
813 " delete : D <key> \n"
818 int main(int argc, char **argv)
821 char *s, buf[BUFLEN];
828 s = fgets(buf, BUFLEN-1, stdin);
835 ret = sscanf(s+1, "%lu", &key);
837 pset_insert(ps, key);
842 ret = sscanf(s+1, "%lu", &key);
844 ret = pset_lookup(ps, key);
845 printf("%lu -> %s\n", key, ret ? "true" : "false");
850 ret = sscanf(s+1, "%lu", &key);
852 pset_delete(ps, key);
857 printf("%lu\n", pset_elements(ps));
881 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4