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
17 static inline xhashidx hash_int(xhashidx key)
22 static inline int cmp_int(xhashidx key1, xhashidx key2)
24 return (key1 == key2);
27 static inline xhashidx hash_string(xhashidx key)
29 //assume a valid NULL terminated string
31 //function to access key if in container
32 char *string = (char *) key;
33 unsigned int i, len = strlen(string);
34 xhashidx hv = string[0] << 7;
35 for (i = 1; i <= len; i++) {
36 hv = (hv * 1000003) ^ string[i];
41 // XSEGLOG("String %s (%lx). Hash value: %llu",
42 // string, string, hv);
46 static inline int cmp_string(xhashidx key1, xhashidx key2)
48 char *string1 = (char *) key1;
49 char *string2 = (char *) key2;
50 int value = !strcmp(string1, string2);
51 // XSEGLOG("String1 %s (%lx), string2: %s(%lx), r: %d",
52 // string1, (unsigned long) string1,
53 // string2, (unsigned long) string2,
59 typedef int (*xhash_cmp_fun_t)(xhashidx key1, xhashidx key2);
60 typedef xhashidx (*xhash_hash_fun_t)(xhashidx key);
62 struct types_functions {
63 // int (*cmp_fun)(xhashidx key1, xhashidx key2);
64 // xhashidx (*hash_fun)(xhashidx key);
65 xhash_cmp_fun_t cmp_fun;
66 xhash_hash_fun_t hash_fun;
69 static struct types_functions types_fun[] = {
70 { .cmp_fun = cmp_int, .hash_fun = hash_int },
71 { .cmp_fun = cmp_string, .hash_fun = hash_string }
76 set_dummy_key(xhash_t *xhash, xhashidx idx)
78 xhashidx *kvs = xhash_kvs(xhash);
83 set_dummy_val(xhash_t *xhash, xhashidx idx)
85 xhashidx *vals = xhash_vals(xhash);
90 item_dummy(xhash_t *xhash, xhashidx idx, bool vals)
94 xhashidx *kvs = xhash_kvs(xhash);
97 ret = (kvs[idx] == DUMMY);
99 #if defined(VAL_OVERLOAD)
100 pvals = xhash_vals(xhash);
101 ret = (pvals[idx] == DUMMY);
102 #elif defined(KEY_OVERLOAD)
103 ret = (kvs[idx] == DUMMY);
110 static void set_dummy_item(xhash_t *xhash, xhashidx idx, bool vals)
113 set_dummy_key(xhash, idx);
118 set_dummy_val(xhash, idx);
120 #elif defined(KEY_OVERLOAD)
121 set_dummy_key(xhash, idx);
126 set_unused_key(xhash_t *xhash, xhashidx idx)
128 xhashidx *kvs = xhash_kvs(xhash);
133 set_unused_val(xhash_t *xhash, xhashidx idx)
135 xhashidx *vals = xhash_vals(xhash);
140 val_unused(xhash_t *xhash, xhashidx idx)
142 xhashidx *vals = xhash_vals(xhash);
143 return vals[idx] == UNUSED;
147 item_unused(xhash_t *xhash, xhashidx idx, bool vals)
149 xhashidx *kvs = xhash_kvs(xhash);
151 return kvs[idx] == UNUSED;
154 #if defined(VAL_OVERLOAD)
155 return val_unused(xhash, idx);
156 #elif defined(KEY_OVERLOAD)
157 return kvs[idx] == UNUSED;
162 static inline unsigned item_valid(xhash_t *xhash, xhashidx idx, bool vals)
164 return !(item_dummy(xhash, idx, vals) || item_unused(xhash, idx, vals));
167 static void __attribute__((unused))
168 assert_key(xhashidx key)
170 assert((key != UNUSED) && (key != DUMMY));
174 assert_val(xhashidx val)
176 assert((val != UNUSED) && (val != DUMMY));
180 assert_kv(xhashidx k, xhashidx v)
182 #if defined(KEY_OVERLOAD)
184 #elif defined(VAL_OVERLOAD)
191 xhash_init__(xhash_t *xhash, xhashidx size_shift, xhashidx minsize_shift,
192 enum xhash_type type, bool vals)
194 xhashidx nr_items = 1UL << size_shift;
195 xhashidx *kvs = (xhashidx *) ((char *) xhash + sizeof(struct xhash));
198 XPTRSET(&xhash->kvs, kvs);
202 for (i=0; i < nr_items; i++)
207 for (i=0; i < nr_items; i++){
208 #if defined(VAL_OVERLOAD)
209 kvs[nr_items + i] = UNUSED;
210 #elif defined(KEY_OVERLOAD)
216 xhash->dummies = xhash->used = 0;
217 xhash->size_shift = size_shift;
218 xhash->minsize_shift = minsize_shift;
221 ZEROSTAT(xhash->inserts);
222 ZEROSTAT(xhash->deletes);
223 ZEROSTAT(xhash->lookups);
224 ZEROSTAT(xhash->bounces);
228 get_alloc_size(xhashidx size_shift, bool vals)
230 xhashidx nr_items = 1UL << size_shift;
231 size_t keys_size = nr_items*sizeof(xhashidx);
232 size_t alloc_size = vals ? keys_size<<1 : keys_size;
233 return sizeof(struct xhash) + alloc_size;
238 xhash_new__(xhashidx size_shift, xhashidx minsize_shift,
239 enum xhash_type type, bool vals)
242 xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
244 XSEGLOG("couldn't malloc\n");
248 xhash_init__(xhash, size_shift, minsize_shift, type, vals);
255 xhash_resize__(struct xhash *xhash, xhashidx new_size_shift, bool vals)
257 return xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, vals);
261 xhash_delete__(xhash_t *xhash, xhashidx key, bool vals)
263 // XSEGLOG("Deleting %lx", key);
264 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
265 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
266 xhashidx perturb = hash_fun(key);
267 xhashidx mask = xhash_size(xhash)-1;
268 xhashidx idx = hash_fun(key) & mask;
269 xhashidx *kvs = xhash_kvs(xhash);
272 if ( item_unused(xhash, idx, vals) ){
276 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
277 INCSTAT(xhash->deletes);
278 set_dummy_item(xhash, idx, vals);
280 //fprintf(stderr, "rm: used: %lu\n", xhash->used);
285 INCSTAT(xhash->bounces);
286 idx = ((idx<<2) + idx + 1 + perturb) & mask;
287 perturb >>= PERTURB_SHIFT;
292 xhash_grow_size_shift(xhash_t *xhash)
294 xhashidx old_size_shift = xhash->size_shift;
295 xhashidx new_size_shift;
299 //printf("used: %lu\n", u);
300 if (u/2 + u >= ((xhashidx)1 << old_size_shift)) {
301 new_size_shift = old_size_shift + 1;
303 new_size_shift = old_size_shift;
306 return new_size_shift;
310 xhash_shrink_size_shift(xhash_t *xhash)
312 xhashidx old_size_shift = xhash->size_shift;
313 xhashidx new_size_shift;
314 new_size_shift = old_size_shift - 1;
315 if (new_size_shift < xhash->minsize_shift) {
316 new_size_shift = xhash->minsize_shift;
318 return new_size_shift;
322 grow_check(xhash_t *xhash)
324 xhashidx size_shift = xhash->size_shift;
325 xhashidx u = xhash->used + xhash->dummies;
326 xhashidx size = (xhashidx)1UL<<size_shift;
327 return ((u/2 + u) >= size) ? true : false;
331 shrink_check(xhash_t *xhash)
333 xhashidx size_shift = xhash->size_shift;
334 xhashidx size = (xhashidx)1<<size_shift;
335 xhashidx u = xhash->used;
336 return (4*u < size && size_shift > xhash->minsize_shift) ? true : false;
345 xhash_get_alloc_size(xhashidx size_shift)
347 return get_alloc_size(size_shift, true);
351 xhash_new(xhashidx minsize_shift, enum xhash_type type)
353 return xhash_new__(minsize_shift, minsize_shift, type, true);
356 void xhash_free(struct xhash *xhash)
361 void xhash_init(struct xhash *xhash, xhashidx minsize_shift, enum xhash_type type)
363 xhash_init__(xhash, minsize_shift, minsize_shift, type, true);
368 xhash_grow(struct xhash *xhash)
370 xhashidx new_size_shift = xhash_grow_size_shift(xhash);
371 return xhash_resize(xhash, new_size_shift);
375 xhash_shrink(struct xhash *xhash)
377 xhashidx new_size_shift = xhash_shrink_size_shift(xhash);
378 return xhash_resize(xhash, new_size_shift);
381 static inline xhash_t*
382 xhash_grow_check(xhash_t *xhash)
384 if (grow_check(xhash))
385 return xhash_grow(xhash);
391 #define PHASH_UPDATE(xhash, key, val, vals_flag) \
393 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun; \
394 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun; \
395 xhashidx size = 1UL<<(xhash->size_shift); \
396 xhashidx perturb = hash_fun(key); \
397 xhashidx mask = size-1; \
398 xhashidx idx = hash_fun(key) & mask; \
399 xhashidx *kvs = xhash_kvs(xhash); \
401 INCSTAT(xhash->inserts); \
403 if ( !item_valid(xhash, idx, vals_flag) ){ \
404 PHUPD_SET__(xhash, idx, key, val); \
407 if (cmp_fun(kvs[idx], key)){ \
408 PHUPD_UPDATE__(xhash, idx, key, val); \
412 again: __attribute__((unused)) \
413 INCSTAT(xhash->bounces); \
414 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
415 perturb >>= PERTURB_SHIFT; \
420 set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
422 xhashidx *kvs = xhash_kvs(p);
423 xhashidx *vals = xhash_vals(p);
426 //XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
429 void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
431 xhashidx *kvs = xhash_kvs(p);
432 xhashidx *vals = xhash_vals(p);
433 if (item_dummy(p, idx, true))
438 //XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
442 inc_val(xhash_t *p, xhashidx idx, xhashidx val)
444 xhashidx *vals = xhash_vals(p);
448 void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
450 //XSEGLOG("inserting %lx", key);
451 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
452 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
453 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
454 PHASH_UPDATE(xhash, key, val, true)
455 #undef PHUPD_UPDATE__
459 int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
461 if (grow_check(xhash))
462 return -XHASH_ERESIZE;
463 xhash_insert__(xhash, key, val);
468 void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
470 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
471 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
472 PHASH_UPDATE(xhash, key, val, true)
473 #undef PHUPD_UPDATE__
477 int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
479 if (grow_check(xhash))
480 return -XHASH_ERESIZE;
481 xhash_freql_update__(xhash, key, val);
486 xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhash_t *new)
488 //XSEGLOG("Resizing xhash from %llu to %llu", xhash->size_shift, new_size_shift);
492 new = xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, true);
494 xhash_init__(new, new_size_shift, xhash->minsize_shift, xhash->type, true);
499 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
500 for (i = 0; i < xhash_size(xhash); i++) {
501 if (item_valid(xhash, i, true)){
502 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
503 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
513 * note that his function does not modify the internal structure of the hash
514 * and thus its safe to use it for updating values during a xhash_iterate()
516 int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
518 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
519 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
520 #define PHUPD_SET__(_p, _i, _k, _v) goto again
521 PHASH_UPDATE(xhash, key, val, true)
522 #undef PHUPD_UPDATE__
529 int xhash_delete(struct xhash *xhash, xhashidx key)
531 if (shrink_check(xhash))
532 return -XHASH_ERESIZE;
533 return xhash_delete__(xhash, key, true);
536 int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
538 //XSEGLOG("looking up %lx", key);
539 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
540 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
541 xhashidx size_shift = xhash->size_shift;
542 xhashidx size = (1UL)<<size_shift;
543 xhashidx perturb = hash_fun(key);
544 xhashidx mask = size-1;
545 xhashidx idx = hash_fun(key) & mask;
546 xhashidx *kvs = xhash_kvs(xhash);
548 INCSTAT(xhash->lookups);
550 //XSEGLOG("size %llu, perturb %llu idx %llu mask %llu",
551 // size, perturb, idx, mask);
552 if ( item_unused(xhash, idx, vals) )
553 return -XHASH_EEXIST;
555 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
560 INCSTAT(xhash->bounces);
561 idx = ((idx<<2) + idx + 1 + perturb) & mask;
562 perturb >>= PERTURB_SHIFT;
566 int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
569 int ret = xhash_lookup__(xhash, key, &idx, true);
571 xhashidx *values = xhash_vals(xhash);
577 //FIXME iteration broken
579 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
581 pi->cnt = pi->loc = 0;
585 xhash_iterate__(xhash_t *xhash, bool vals,
586 xhash_iter_t *pi, xhashidx *key_ret, xhashidx *idx_ret)
588 xhashidx idx = pi->loc;
589 xhashidx size = (xhashidx)1<<xhash->size_shift;
590 xhashidx *kvs = xhash_kvs(xhash);
591 INCSTAT(xhash->lookups);
593 if (xhash->used == pi->cnt || idx >= size)
596 if (item_valid(xhash, idx, vals)){
608 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
611 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
613 xhashidx *vals = xhash_vals(xhash);
619 void xhash_print(xhash_t *xhash)
625 xhash_iter_init(xhash, &pi);
626 XSEGLOG("PHASH(%p):\n", xhash);
628 ret = xhash_iterate(xhash, &pi, &key, &val);
632 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
642 " insert : I <key> <val> \n"
643 " update : U <key> <val> (->v += val if exists) \n"
645 " delete : D <key> \n"
650 int main(int argc, char **argv)
653 char *s, buf[BUFLEN];
657 ph = xhash_new(2, INTEGER);
660 s = fgets(buf, BUFLEN-1, stdin);
667 ret = sscanf(s+1, "%lu %lu", &key, &val);
669 xhash_insert(ph, key, val);
674 ret = sscanf(s+1, "%lu %lu", &key, &val);
676 xhash_freql_update(ph, key, val);
681 ret = sscanf(s+1, "%lu", &key);
683 ret = xhash_lookup(ph, key, &val);
685 printf("%lu\n", val);
693 ret = sscanf(s+1, "%lu", &key);
695 xhash_delete(ph, key);
700 printf("%lu\n", xhash_elements(ph));
728 pset_new(xhashidx minsize_shift)
731 pset = malloc(sizeof(pset_t));
736 xhash_init__(&pset->ph_, minsize_shift, false);
741 pset_init(pset_t *pset, xhashidx minsize_shift)
743 xhash_init__(&pset->ph_, minsize_shift, false);
747 pset_free(pset_t *pset)
749 xhash_tfree(&pset->ph_);
754 pset_tfree(pset_t *pset)
756 xhash_tfree(&pset->ph_);
760 pset_resize(pset_t *pset, xhashidx new_size_shift)
763 xhash_cp(&(old.ph_), &pset->ph_);
765 xhash_resize__(&pset->ph_, new_size_shift, false);
766 for (xhashidx i = 0; i < pset_size(&old); i++) {
767 if (item_valid(&(old.ph_), i, false)){
768 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
769 pset_insert(pset, old.ph_.kvs[i]);
776 pset_grow(pset_t *pset)
778 xhashidx new_size_shift = grow_size_shift(&pset->ph_);
779 pset_resize(pset, new_size_shift);
783 pset_grow_check(pset_t *pset)
785 if (grow_check(&pset->ph_))
789 void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
791 if (item_dummy(p, idx, false))
797 void pset_insert(pset_t *pset, xhashidx key)
799 xhash_t *ph = &pset->ph_;
801 pset_grow_check(pset);
802 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
803 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
804 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
805 #undef PHUPD_UPDATE__
810 pset_shrink(pset_t *pset)
812 xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
813 pset_resize(pset, new_size_shift);
816 int pset_delete(pset_t *pset, xhashidx key)
818 if (pset->ph_.used == 0)
822 xhashidx size_shift = pset->ph_.size_shift;
823 xhashidx size = (xhashidx)1<<size_shift;
824 xhashidx u = pset->ph_.used;
827 return xhash_delete__(&pset->ph_, key, false);
830 bool pset_lookup(pset_t *pset, xhashidx key)
833 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
836 int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
839 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
843 void pset_print(pset_t *pset)
849 pset_iter_init(pset, &pi);
850 printf("PSET(%p):\n", pset);
852 ret = pset_iterate(pset, &pi, &key);
856 printf(" 0x%017lx\n", key);
861 #if defined(PSET_MAIN)
866 " insert : I <key> <val> \n"
868 " delete : D <key> \n"
873 int main(int argc, char **argv)
876 char *s, buf[BUFLEN];
883 s = fgets(buf, BUFLEN-1, stdin);
890 ret = sscanf(s+1, "%lu", &key);
892 pset_insert(ps, key);
897 ret = sscanf(s+1, "%lu", &key);
899 ret = pset_lookup(ps, key);
900 printf("%lu -> %s\n", key, ret ? "true" : "false");
905 ret = sscanf(s+1, "%lu", &key);
907 pset_delete(ps, key);
912 printf("%lu\n", pset_elements(ps));
938 #include <linux/module.h>
939 #include <xtypes/xhash_exports.h>
942 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4