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, bool vals)
135 xhashidx nr_items = 1UL << size_shift;
136 xhashidx *kvs = (xhashidx *) ((char *) xhash + sizeof(struct xhash));
139 XPTRSET(&xhash->kvs, kvs);
143 for (i=0; i < nr_items; i++)
148 for (i=0; i < nr_items; i++){
149 #if defined(VAL_OVERLOAD)
150 kvs[nr_items + i] = UNUSED;
151 #elif defined(KEY_OVERLOAD)
157 xhash->dummies = xhash->used = 0;
158 xhash->size_shift = size_shift;
159 xhash->minsize_shift = minsize_shift;
161 ZEROSTAT(xhash->inserts);
162 ZEROSTAT(xhash->deletes);
163 ZEROSTAT(xhash->lookups);
164 ZEROSTAT(xhash->bounces);
168 get_alloc_size(xhashidx size_shift, bool vals)
170 xhashidx nr_items = 1UL << size_shift;
171 size_t keys_size = nr_items*sizeof(xhashidx);
172 size_t alloc_size = vals ? keys_size<<1 : keys_size;
173 return sizeof(struct xhash) + alloc_size;
178 xhash_new__(xhashidx size_shift, xhashidx minsize_shift, bool vals) {
180 xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
182 XSEGLOG("couldn't malloc\n");
186 xhash_init__(xhash, size_shift, minsize_shift, vals);
193 xhash_resize__(struct xhash *xhash, xhashidx new_size_shift, bool vals)
195 return xhash_new__(new_size_shift, xhash->minsize_shift, vals);
199 xhash_delete__(xhash_t *xhash, xhashidx key, bool vals)
201 xhashidx perturb = key;
202 xhashidx mask = xhash_size(xhash)-1;
203 xhashidx idx = key & mask;
204 xhashidx *kvs = xhash_kvs(xhash);
207 if ( item_unused(xhash, idx, vals) ){
211 if ( !item_dummy(xhash, idx, vals) && kvs[idx] == key){
212 INCSTAT(xhash->deletes);
213 set_dummy_item(xhash, idx, vals);
215 //fprintf(stderr, "rm: used: %lu\n", xhash->used);
220 INCSTAT(xhash->bounces);
221 idx = ((idx<<2) + idx + 1 + perturb) & mask;
222 perturb >>= PERTURB_SHIFT;
227 xhash_grow_size_shift(xhash_t *xhash)
229 xhashidx old_size_shift = xhash->size_shift;
230 xhashidx new_size_shift;
234 //printf("used: %lu\n", u);
235 if (u/2 + u >= ((xhashidx)1 << old_size_shift)) {
236 new_size_shift = old_size_shift + 1;
238 new_size_shift = old_size_shift;
241 return new_size_shift;
245 xhash_shrink_size_shift(xhash_t *xhash)
247 xhashidx old_size_shift = xhash->size_shift;
248 xhashidx new_size_shift;
249 new_size_shift = old_size_shift - 1;
250 if (new_size_shift < xhash->minsize_shift) {
251 new_size_shift = xhash->minsize_shift;
253 return new_size_shift;
257 grow_check(xhash_t *xhash)
259 xhashidx size_shift = xhash->size_shift;
260 xhashidx u = xhash->used + xhash->dummies;
261 xhashidx size = (xhashidx)1UL<<size_shift;
262 return ((u/2 + u) >= size) ? true : false;
266 shrink_check(xhash_t *xhash)
268 xhashidx size_shift = xhash->size_shift;
269 xhashidx size = (xhashidx)1<<size_shift;
270 xhashidx u = xhash->used;
271 return (4*u < size && size_shift > xhash->minsize_shift) ? true : false;
280 xhash_get_alloc_size(xhashidx size_shift)
282 return get_alloc_size(size_shift, true);
286 xhash_new(xhashidx minsize_shift)
288 return xhash_new__(minsize_shift, minsize_shift, true);
291 void xhash_free(struct xhash *xhash)
296 void xhash_init(struct xhash *xhash, xhashidx minsize_shift)
298 xhash_init__(xhash, minsize_shift, minsize_shift, true);
303 xhash_grow(struct xhash *xhash)
305 xhashidx new_size_shift = xhash_grow_size_shift(xhash);
306 return xhash_resize(xhash, new_size_shift);
310 xhash_shrink(struct xhash *xhash)
312 xhashidx new_size_shift = xhash_shrink_size_shift(xhash);
313 return xhash_resize(xhash, new_size_shift);
316 static inline xhash_t*
317 xhash_grow_check(xhash_t *xhash)
319 if (grow_check(xhash))
320 return xhash_grow(xhash);
326 #define PHASH_UPDATE(xhash, key, val, vals_flag) \
328 xhashidx size = 1UL<<(xhash->size_shift); \
329 xhashidx perturb = key; \
330 xhashidx mask = size-1; \
331 xhashidx idx = key & mask; \
332 xhashidx *kvs = xhash_kvs(xhash); \
334 INCSTAT(xhash->inserts); \
336 if ( !item_valid(xhash, idx, vals_flag) ){ \
337 PHUPD_SET__(xhash, idx, key, val); \
340 if (kvs[idx] == key){ \
341 PHUPD_UPDATE__(xhash, idx, key, val); \
345 again: __attribute__((unused)) \
346 INCSTAT(xhash->bounces); \
347 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
348 perturb >>= PERTURB_SHIFT; \
353 set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
355 xhashidx *kvs = xhash_kvs(p);
356 xhashidx *vals = xhash_vals(p);
361 void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
363 xhashidx *kvs = xhash_kvs(p);
364 xhashidx *vals = xhash_vals(p);
365 if (item_dummy(p, idx, true))
373 inc_val(xhash_t *p, xhashidx idx, xhashidx val)
375 xhashidx *vals = xhash_vals(p);
379 void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
381 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
382 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
383 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
384 PHASH_UPDATE(xhash, key, val, true)
385 #undef PHUPD_UPDATE__
389 int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
391 if (grow_check(xhash))
392 return -XHASH_ERESIZE;
393 xhash_insert__(xhash, key, val);
398 void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
400 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
401 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
402 PHASH_UPDATE(xhash, key, val, true)
403 #undef PHUPD_UPDATE__
407 int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
409 if (grow_check(xhash))
410 return -XHASH_ERESIZE;
411 xhash_freql_update__(xhash, key, val);
416 xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhash_t *new)
421 new = xhash_new__(new_size_shift, xhash->minsize_shift, true);
423 xhash_init__(new, new_size_shift, xhash->minsize_shift, true);
428 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
429 for (i = 0; i < xhash_size(xhash); i++) {
430 if (item_valid(xhash, i, true)){
431 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
432 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
442 * note that his function does not modify the internal structure of the hash
443 * and thus its safe to use it for updating values during a xhash_iterate()
445 int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
447 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
448 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
449 #define PHUPD_SET__(_p, _i, _k, _v) goto again
450 PHASH_UPDATE(xhash, key, val, true)
451 #undef PHUPD_UPDATE__
458 int xhash_delete(struct xhash *xhash, xhashidx key)
460 if (shrink_check(xhash))
461 return -XHASH_ERESIZE;
462 return xhash_delete__(xhash, key, true);
465 int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
467 xhashidx size_shift = xhash->size_shift;
468 xhashidx size = (xhashidx)1<<size_shift;
469 xhashidx perturb = key;
470 xhashidx mask = size-1;
471 xhashidx idx = key & mask;
472 xhashidx *kvs = xhash_kvs(xhash);
474 INCSTAT(xhash->lookups);
476 if ( item_unused(xhash, idx, vals) )
477 return -XHASH_EEXIST;
479 if ( !item_dummy(xhash, idx, vals) && kvs[idx] == key){
484 INCSTAT(xhash->bounces);
485 idx = ((idx<<2) + idx + 1 + perturb) & mask;
486 perturb >>= PERTURB_SHIFT;
490 int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
493 int ret = xhash_lookup__(xhash, key, &idx, true);
495 xhashidx *values = xhash_vals(xhash);
502 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
504 pi->cnt = pi->loc = 0;
508 xhash_iterate__(xhash_t *xhash, bool vals,
509 xhash_iter_t *pi, xhashidx *key_ret, xhashidx *idx_ret)
511 xhashidx idx = pi->loc;
512 xhashidx size = (xhashidx)1<<xhash->size_shift;
513 xhashidx *kvs = xhash_kvs(xhash);
514 INCSTAT(xhash->lookups);
516 if (xhash->used == pi->cnt || idx >= size)
519 if (item_valid(xhash, idx, vals)){
531 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
534 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
536 xhashidx *vals = xhash_vals(xhash);
542 void xhash_print(xhash_t *xhash)
548 xhash_iter_init(xhash, &pi);
549 XSEGLOG("PHASH(%p):\n", xhash);
551 ret = xhash_iterate(xhash, &pi, &key, &val);
555 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
565 " insert : I <key> <val> \n"
566 " update : U <key> <val> (->v += val if exists) \n"
568 " delete : D <key> \n"
573 int main(int argc, char **argv)
576 char *s, buf[BUFLEN];
583 s = fgets(buf, BUFLEN-1, stdin);
590 ret = sscanf(s+1, "%lu %lu", &key, &val);
592 xhash_insert(ph, key, val);
597 ret = sscanf(s+1, "%lu %lu", &key, &val);
599 xhash_freql_update(ph, key, val);
604 ret = sscanf(s+1, "%lu", &key);
606 ret = xhash_lookup(ph, key, &val);
608 printf("%lu\n", val);
616 ret = sscanf(s+1, "%lu", &key);
618 xhash_delete(ph, key);
623 printf("%lu\n", xhash_elements(ph));
651 pset_new(xhashidx minsize_shift)
654 pset = malloc(sizeof(pset_t));
659 xhash_init__(&pset->ph_, minsize_shift, false);
664 pset_init(pset_t *pset, xhashidx minsize_shift)
666 xhash_init__(&pset->ph_, minsize_shift, false);
670 pset_free(pset_t *pset)
672 xhash_tfree(&pset->ph_);
677 pset_tfree(pset_t *pset)
679 xhash_tfree(&pset->ph_);
683 pset_resize(pset_t *pset, xhashidx new_size_shift)
686 xhash_cp(&(old.ph_), &pset->ph_);
688 xhash_resize__(&pset->ph_, new_size_shift, false);
689 for (xhashidx i = 0; i < pset_size(&old); i++) {
690 if (item_valid(&(old.ph_), i, false)){
691 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
692 pset_insert(pset, old.ph_.kvs[i]);
699 pset_grow(pset_t *pset)
701 xhashidx new_size_shift = grow_size_shift(&pset->ph_);
702 pset_resize(pset, new_size_shift);
706 pset_grow_check(pset_t *pset)
708 if (grow_check(&pset->ph_))
712 void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
714 if (item_dummy(p, idx, false))
720 void pset_insert(pset_t *pset, xhashidx key)
722 xhash_t *ph = &pset->ph_;
724 pset_grow_check(pset);
725 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
726 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
727 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
728 #undef PHUPD_UPDATE__
733 pset_shrink(pset_t *pset)
735 xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
736 pset_resize(pset, new_size_shift);
739 int pset_delete(pset_t *pset, xhashidx key)
741 if (pset->ph_.used == 0)
745 xhashidx size_shift = pset->ph_.size_shift;
746 xhashidx size = (xhashidx)1<<size_shift;
747 xhashidx u = pset->ph_.used;
750 return xhash_delete__(&pset->ph_, key, false);
753 bool pset_lookup(pset_t *pset, xhashidx key)
756 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
759 int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
762 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
766 void pset_print(pset_t *pset)
772 pset_iter_init(pset, &pi);
773 printf("PSET(%p):\n", pset);
775 ret = pset_iterate(pset, &pi, &key);
779 printf(" 0x%017lx\n", key);
784 #if defined(PSET_MAIN)
789 " insert : I <key> <val> \n"
791 " delete : D <key> \n"
796 int main(int argc, char **argv)
799 char *s, buf[BUFLEN];
806 s = fgets(buf, BUFLEN-1, stdin);
813 ret = sscanf(s+1, "%lu", &key);
815 pset_insert(ps, key);
820 ret = sscanf(s+1, "%lu", &key);
822 ret = pset_lookup(ps, key);
823 printf("%lu -> %s\n", key, ret ? "true" : "false");
828 ret = sscanf(s+1, "%lu", &key);
830 pset_delete(ps, key);
835 printf("%lu\n", pset_elements(ps));
859 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4