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",
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 XSEGLOG("size %llu, perturb %llu idx %llu mask %llu",\
404 size, perturb, idx, mask); \
405 if ( !item_valid(xhash, idx, vals_flag) ){ \
406 PHUPD_SET__(xhash, idx, key, val); \
409 if (cmp_fun(kvs[idx], key)){ \
410 PHUPD_UPDATE__(xhash, idx, key, val); \
414 again: __attribute__((unused)) \
415 INCSTAT(xhash->bounces); \
416 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
417 perturb >>= PERTURB_SHIFT; \
422 set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
424 xhashidx *kvs = xhash_kvs(p);
425 xhashidx *vals = xhash_vals(p);
428 XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
431 void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
433 xhashidx *kvs = xhash_kvs(p);
434 xhashidx *vals = xhash_vals(p);
435 if (item_dummy(p, idx, true))
440 XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
444 inc_val(xhash_t *p, xhashidx idx, xhashidx val)
446 xhashidx *vals = xhash_vals(p);
450 void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
452 XSEGLOG("inserting %lx", key);
453 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
454 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
455 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
456 PHASH_UPDATE(xhash, key, val, true)
457 #undef PHUPD_UPDATE__
461 int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
463 if (grow_check(xhash))
464 return -XHASH_ERESIZE;
465 xhash_insert__(xhash, key, val);
470 void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
472 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
473 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
474 PHASH_UPDATE(xhash, key, val, true)
475 #undef PHUPD_UPDATE__
479 int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
481 if (grow_check(xhash))
482 return -XHASH_ERESIZE;
483 xhash_freql_update__(xhash, key, val);
488 xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhash_t *new)
490 XSEGLOG("Resizing xhash from %llu to %llu", xhash->size_shift, new_size_shift);
494 new = xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, true);
496 xhash_init__(new, new_size_shift, xhash->minsize_shift, xhash->type, true);
501 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
502 for (i = 0; i < xhash_size(xhash); i++) {
503 if (item_valid(xhash, i, true)){
504 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
505 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
515 * note that his function does not modify the internal structure of the hash
516 * and thus its safe to use it for updating values during a xhash_iterate()
518 int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
520 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
521 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
522 #define PHUPD_SET__(_p, _i, _k, _v) goto again
523 PHASH_UPDATE(xhash, key, val, true)
524 #undef PHUPD_UPDATE__
531 int xhash_delete(struct xhash *xhash, xhashidx key)
533 if (shrink_check(xhash))
534 return -XHASH_ERESIZE;
535 return xhash_delete__(xhash, key, true);
538 int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
540 XSEGLOG("looking up %lx", key);
541 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
542 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
543 xhashidx size_shift = xhash->size_shift;
544 xhashidx size = (1UL)<<size_shift;
545 xhashidx perturb = hash_fun(key);
546 xhashidx mask = size-1;
547 xhashidx idx = hash_fun(key) & mask;
548 xhashidx *kvs = xhash_kvs(xhash);
550 INCSTAT(xhash->lookups);
552 XSEGLOG("size %llu, perturb %llu idx %llu mask %llu",\
553 size, perturb, idx, mask); \
554 if ( item_unused(xhash, idx, vals) )
555 return -XHASH_EEXIST;
557 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
562 INCSTAT(xhash->bounces);
563 idx = ((idx<<2) + idx + 1 + perturb) & mask;
564 perturb >>= PERTURB_SHIFT;
568 int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
571 int ret = xhash_lookup__(xhash, key, &idx, true);
573 xhashidx *values = xhash_vals(xhash);
579 //FIXME iteration broken
581 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
583 pi->cnt = pi->loc = 0;
587 xhash_iterate__(xhash_t *xhash, bool vals,
588 xhash_iter_t *pi, xhashidx *key_ret, xhashidx *idx_ret)
590 xhashidx idx = pi->loc;
591 xhashidx size = (xhashidx)1<<xhash->size_shift;
592 xhashidx *kvs = xhash_kvs(xhash);
593 INCSTAT(xhash->lookups);
595 if (xhash->used == pi->cnt || idx >= size)
598 if (item_valid(xhash, idx, vals)){
610 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
613 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
615 xhashidx *vals = xhash_vals(xhash);
621 void xhash_print(xhash_t *xhash)
627 xhash_iter_init(xhash, &pi);
628 XSEGLOG("PHASH(%p):\n", xhash);
630 ret = xhash_iterate(xhash, &pi, &key, &val);
634 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
644 " insert : I <key> <val> \n"
645 " update : U <key> <val> (->v += val if exists) \n"
647 " delete : D <key> \n"
652 int main(int argc, char **argv)
655 char *s, buf[BUFLEN];
659 ph = xhash_new(2, INTEGER);
662 s = fgets(buf, BUFLEN-1, stdin);
669 ret = sscanf(s+1, "%lu %lu", &key, &val);
671 xhash_insert(ph, key, val);
676 ret = sscanf(s+1, "%lu %lu", &key, &val);
678 xhash_freql_update(ph, key, val);
683 ret = sscanf(s+1, "%lu", &key);
685 ret = xhash_lookup(ph, key, &val);
687 printf("%lu\n", val);
695 ret = sscanf(s+1, "%lu", &key);
697 xhash_delete(ph, key);
702 printf("%lu\n", xhash_elements(ph));
730 pset_new(xhashidx minsize_shift)
733 pset = malloc(sizeof(pset_t));
738 xhash_init__(&pset->ph_, minsize_shift, false);
743 pset_init(pset_t *pset, xhashidx minsize_shift)
745 xhash_init__(&pset->ph_, minsize_shift, false);
749 pset_free(pset_t *pset)
751 xhash_tfree(&pset->ph_);
756 pset_tfree(pset_t *pset)
758 xhash_tfree(&pset->ph_);
762 pset_resize(pset_t *pset, xhashidx new_size_shift)
765 xhash_cp(&(old.ph_), &pset->ph_);
767 xhash_resize__(&pset->ph_, new_size_shift, false);
768 for (xhashidx i = 0; i < pset_size(&old); i++) {
769 if (item_valid(&(old.ph_), i, false)){
770 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
771 pset_insert(pset, old.ph_.kvs[i]);
778 pset_grow(pset_t *pset)
780 xhashidx new_size_shift = grow_size_shift(&pset->ph_);
781 pset_resize(pset, new_size_shift);
785 pset_grow_check(pset_t *pset)
787 if (grow_check(&pset->ph_))
791 void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
793 if (item_dummy(p, idx, false))
799 void pset_insert(pset_t *pset, xhashidx key)
801 xhash_t *ph = &pset->ph_;
803 pset_grow_check(pset);
804 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
805 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
806 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
807 #undef PHUPD_UPDATE__
812 pset_shrink(pset_t *pset)
814 xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
815 pset_resize(pset, new_size_shift);
818 int pset_delete(pset_t *pset, xhashidx key)
820 if (pset->ph_.used == 0)
824 xhashidx size_shift = pset->ph_.size_shift;
825 xhashidx size = (xhashidx)1<<size_shift;
826 xhashidx u = pset->ph_.used;
829 return xhash_delete__(&pset->ph_, key, false);
832 bool pset_lookup(pset_t *pset, xhashidx key)
835 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
838 int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
841 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
845 void pset_print(pset_t *pset)
851 pset_iter_init(pset, &pi);
852 printf("PSET(%p):\n", pset);
854 ret = pset_iterate(pset, &pi, &key);
858 printf(" 0x%017lx\n", key);
863 #if defined(PSET_MAIN)
868 " insert : I <key> <val> \n"
870 " delete : D <key> \n"
875 int main(int argc, char **argv)
878 char *s, buf[BUFLEN];
885 s = fgets(buf, BUFLEN-1, stdin);
892 ret = sscanf(s+1, "%lu", &key);
894 pset_insert(ps, key);
899 ret = sscanf(s+1, "%lu", &key);
901 ret = pset_lookup(ps, key);
902 printf("%lu -> %s\n", key, ret ? "true" : "false");
907 ret = sscanf(s+1, "%lu", &key);
909 pset_delete(ps, key);
914 printf("%lu\n", pset_elements(ps));
940 #include <linux/module.h>
941 #include <xtypes/xhash_exports.h>
944 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4