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);
445 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
446 for (i = 0; i < xhash_size(xhash); i++) {
447 if (item_valid(xhash, i, true)){
448 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
449 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
459 * note that his function does not modify the internal structure of the hash
460 * and thus its safe to use it for updating values during a xhash_iterate()
462 int xhash_update(struct xhash *xhash, ul_t key, ul_t val) {
464 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
466 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
467 #define PHUPD_SET__(_p, _i, _k, _v) goto again
468 PHASH_UPDATE(xhash, key, val, true)
469 #undef PHUPD_UPDATE__
476 int xhash_delete(struct xhash *xhash, ul_t key)
478 #if defined(KEY_OVERLOAD)
481 if (shrink_check(xhash))
482 return -XHASH_ERESIZE;
483 return xhash_delete__(xhash, key, true);
486 int xhash_lookup__(xhash_t *xhash, ul_t key, ul_t *idx_ret, bool vals)
488 #if defined(KEY_OVERLOAD)
492 ul_t size_shift = xhash->size_shift;
493 ul_t size = (ul_t)1<<size_shift;
496 ul_t idx = key & mask;
497 ul_t *kvs = xhash_kvs(xhash);
499 INCSTAT(xhash->lookups);
501 if ( item_unused(xhash, idx, vals) )
502 return -XHASH_EEXIST;
504 if ( !item_dummy(xhash, idx, vals) && kvs[idx] == key){
509 INCSTAT(xhash->bounces);
510 idx = ((idx<<2) + idx + 1 + perturb) & mask;
511 perturb >>= PERTURB_SHIFT;
515 int xhash_lookup(struct xhash *xhash, ul_t key, ul_t *val)
518 int ret = xhash_lookup__(xhash, key, &idx, true);
520 ul_t *values = xhash_vals(xhash);
527 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
529 pi->cnt = pi->loc = 0;
533 xhash_iterate__(xhash_t *xhash, bool vals,
534 xhash_iter_t *pi, ul_t *key_ret, ul_t *idx_ret)
537 ul_t size = (ul_t)1<<xhash->size_shift;
538 ul_t *kvs = xhash_kvs(xhash);
539 INCSTAT(xhash->lookups);
541 if (xhash->used == pi->cnt || idx >= size)
544 if (item_valid(xhash, idx, vals)){
556 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, ul_t *key, ul_t *val)
559 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
561 ul_t *vals = xhash_vals(xhash);
567 void xhash_print(xhash_t *xhash)
573 xhash_iter_init(xhash, &pi);
574 XSEGLOG("PHASH(%p):\n", xhash);
576 ret = xhash_iterate(xhash, &pi, &key, &val);
580 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
590 " insert : I <key> <val> \n"
591 " update : U <key> <val> (->v += val if exists) \n"
593 " delete : D <key> \n"
598 int main(int argc, char **argv)
601 char *s, buf[BUFLEN];
608 s = fgets(buf, BUFLEN-1, stdin);
615 ret = sscanf(s+1, "%lu %lu", &key, &val);
617 xhash_insert(ph, key, val);
622 ret = sscanf(s+1, "%lu %lu", &key, &val);
624 xhash_freql_update(ph, key, val);
629 ret = sscanf(s+1, "%lu", &key);
631 ret = xhash_lookup(ph, key, &val);
633 printf("%lu\n", val);
641 ret = sscanf(s+1, "%lu", &key);
643 xhash_delete(ph, key);
648 printf("%lu\n", xhash_elements(ph));
676 pset_new(ul_t minsize_shift)
679 pset = malloc(sizeof(pset_t));
684 xhash_init__(&pset->ph_, minsize_shift, false);
689 pset_init(pset_t *pset, ul_t minsize_shift)
691 xhash_init__(&pset->ph_, minsize_shift, false);
695 pset_free(pset_t *pset)
697 xhash_tfree(&pset->ph_);
702 pset_tfree(pset_t *pset)
704 xhash_tfree(&pset->ph_);
708 pset_resize(pset_t *pset, ul_t new_size_shift)
711 xhash_cp(&(old.ph_), &pset->ph_);
713 xhash_resize__(&pset->ph_, new_size_shift, false);
714 for (ul_t i = 0; i < pset_size(&old); i++) {
715 if (item_valid(&(old.ph_), i, false)){
716 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
717 pset_insert(pset, old.ph_.kvs[i]);
724 pset_grow(pset_t *pset)
726 ul_t new_size_shift = grow_size_shift(&pset->ph_);
727 pset_resize(pset, new_size_shift);
731 pset_grow_check(pset_t *pset)
733 if (grow_check(&pset->ph_))
737 void static inline pset_upd_set(xhash_t *p, ul_t idx, ul_t key)
739 if (item_dummy(p, idx, false))
745 void pset_insert(pset_t *pset, ul_t key)
747 xhash_t *ph = &pset->ph_;
749 pset_grow_check(pset);
750 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
751 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
752 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
753 #undef PHUPD_UPDATE__
758 pset_shrink(pset_t *pset)
760 ul_t new_size_shift = shrink_size_shift(&pset->ph_);
761 pset_resize(pset, new_size_shift);
764 int pset_delete(pset_t *pset, ul_t key)
766 if (pset->ph_.used == 0)
770 ul_t size_shift = pset->ph_.size_shift;
771 ul_t size = (ul_t)1<<size_shift;
772 ul_t u = pset->ph_.used;
775 return xhash_delete__(&pset->ph_, key, false);
778 bool pset_lookup(pset_t *pset, ul_t key)
781 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
784 int pset_iterate(pset_t *pset, xhash_iter_t *pi, ul_t *key)
787 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
791 void pset_print(pset_t *pset)
797 pset_iter_init(pset, &pi);
798 printf("PSET(%p):\n", pset);
800 ret = pset_iterate(pset, &pi, &key);
804 printf(" 0x%017lx\n", key);
809 #if defined(PSET_MAIN)
814 " insert : I <key> <val> \n"
816 " delete : D <key> \n"
821 int main(int argc, char **argv)
824 char *s, buf[BUFLEN];
831 s = fgets(buf, BUFLEN-1, stdin);
838 ret = sscanf(s+1, "%lu", &key);
840 pset_insert(ps, key);
845 ret = sscanf(s+1, "%lu", &key);
847 ret = pset_lookup(ps, key);
848 printf("%lu -> %s\n", key, ret ? "true" : "false");
853 ret = sscanf(s+1, "%lu", &key);
855 pset_delete(ps, key);
860 printf("%lu\n", pset_elements(ps));
884 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4