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 valind 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];
44 static inline int cmp_string(xhashidx key1, xhashidx key2)
46 char *string1 = (char *) key1;
47 char *string2 = (char *) key2;
49 return (!strcmp(string1, string2));
52 typedef int (*xhash_cmp_fun_t)(xhashidx key1, xhashidx key2);
53 typedef xhashidx (*xhash_hash_fun_t)(xhashidx key);
55 struct types_functions {
56 // int (*cmp_fun)(xhashidx key1, xhashidx key2);
57 // xhashidx (*hash_fun)(xhashidx key);
58 xhash_cmp_fun_t cmp_fun;
59 xhash_hash_fun_t hash_fun;
62 static struct types_functions types_fun[] = {
63 { .cmp_fun = cmp_int, .hash_fun = hash_int },
64 { .cmp_fun = cmp_string, .hash_fun = hash_string }
69 set_dummy_key(xhash_t *xhash, xhashidx idx)
71 xhashidx *kvs = xhash_kvs(xhash);
76 set_dummy_val(xhash_t *xhash, xhashidx idx)
78 xhashidx *vals = xhash_vals(xhash);
83 item_dummy(xhash_t *xhash, xhashidx idx, bool vals)
87 xhashidx *kvs = xhash_kvs(xhash);
90 ret = (kvs[idx] == DUMMY);
92 #if defined(VAL_OVERLOAD)
93 pvals = xhash_vals(xhash);
94 ret = (pvals[idx] == DUMMY);
95 #elif defined(KEY_OVERLOAD)
96 ret = (kvs[idx] == DUMMY);
103 static void set_dummy_item(xhash_t *xhash, xhashidx idx, bool vals)
106 set_dummy_key(xhash, idx);
111 set_dummy_val(xhash, idx);
113 #elif defined(KEY_OVERLOAD)
114 set_dummy_key(xhash, idx);
119 set_unused_key(xhash_t *xhash, xhashidx idx)
121 xhashidx *kvs = xhash_kvs(xhash);
126 set_unused_val(xhash_t *xhash, xhashidx idx)
128 xhashidx *vals = xhash_vals(xhash);
133 val_unused(xhash_t *xhash, xhashidx idx)
135 xhashidx *vals = xhash_vals(xhash);
136 return vals[idx] == UNUSED;
140 item_unused(xhash_t *xhash, xhashidx idx, bool vals)
142 xhashidx *kvs = xhash_kvs(xhash);
144 return kvs[idx] == UNUSED;
147 #if defined(VAL_OVERLOAD)
148 return val_unused(xhash, idx);
149 #elif defined(KEY_OVERLOAD)
150 return kvs[idx] == UNUSED;
155 static inline unsigned item_valid(xhash_t *xhash, xhashidx idx, bool vals)
157 return !(item_dummy(xhash, idx, vals) || item_unused(xhash, idx, vals));
160 static void __attribute__((unused))
161 assert_key(xhashidx key)
163 assert((key != UNUSED) && (key != DUMMY));
167 assert_val(xhashidx val)
169 assert((val != UNUSED) && (val != DUMMY));
173 assert_kv(xhashidx k, xhashidx v)
175 #if defined(KEY_OVERLOAD)
177 #elif defined(VAL_OVERLOAD)
184 xhash_init__(xhash_t *xhash, xhashidx size_shift, xhashidx minsize_shift,
185 enum xhash_type type, bool vals)
187 xhashidx nr_items = 1UL << size_shift;
188 xhashidx *kvs = (xhashidx *) ((char *) xhash + sizeof(struct xhash));
191 XPTRSET(&xhash->kvs, kvs);
195 for (i=0; i < nr_items; i++)
200 for (i=0; i < nr_items; i++){
201 #if defined(VAL_OVERLOAD)
202 kvs[nr_items + i] = UNUSED;
203 #elif defined(KEY_OVERLOAD)
209 xhash->dummies = xhash->used = 0;
210 xhash->size_shift = size_shift;
211 xhash->minsize_shift = minsize_shift;
214 ZEROSTAT(xhash->inserts);
215 ZEROSTAT(xhash->deletes);
216 ZEROSTAT(xhash->lookups);
217 ZEROSTAT(xhash->bounces);
221 get_alloc_size(xhashidx size_shift, bool vals)
223 xhashidx nr_items = 1UL << size_shift;
224 size_t keys_size = nr_items*sizeof(xhashidx);
225 size_t alloc_size = vals ? keys_size<<1 : keys_size;
226 return sizeof(struct xhash) + alloc_size;
231 xhash_new__(xhashidx size_shift, xhashidx minsize_shift,
232 enum xhash_type type, bool vals)
235 xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
237 XSEGLOG("couldn't malloc\n");
241 xhash_init__(xhash, size_shift, minsize_shift, type, vals);
248 xhash_resize__(struct xhash *xhash, xhashidx new_size_shift, bool vals)
250 return xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, vals);
254 xhash_delete__(xhash_t *xhash, xhashidx key, bool vals)
256 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
257 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
258 xhashidx perturb = key;
259 xhashidx mask = xhash_size(xhash)-1;
260 xhashidx idx = hash_fun(key) & mask;
261 xhashidx *kvs = xhash_kvs(xhash);
264 if ( item_unused(xhash, idx, vals) ){
268 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
269 INCSTAT(xhash->deletes);
270 set_dummy_item(xhash, idx, vals);
272 //fprintf(stderr, "rm: used: %lu\n", xhash->used);
277 INCSTAT(xhash->bounces);
278 idx = ((idx<<2) + idx + 1 + perturb) & mask;
279 perturb >>= PERTURB_SHIFT;
284 xhash_grow_size_shift(xhash_t *xhash)
286 xhashidx old_size_shift = xhash->size_shift;
287 xhashidx new_size_shift;
291 //printf("used: %lu\n", u);
292 if (u/2 + u >= ((xhashidx)1 << old_size_shift)) {
293 new_size_shift = old_size_shift + 1;
295 new_size_shift = old_size_shift;
298 return new_size_shift;
302 xhash_shrink_size_shift(xhash_t *xhash)
304 xhashidx old_size_shift = xhash->size_shift;
305 xhashidx new_size_shift;
306 new_size_shift = old_size_shift - 1;
307 if (new_size_shift < xhash->minsize_shift) {
308 new_size_shift = xhash->minsize_shift;
310 return new_size_shift;
314 grow_check(xhash_t *xhash)
316 xhashidx size_shift = xhash->size_shift;
317 xhashidx u = xhash->used + xhash->dummies;
318 xhashidx size = (xhashidx)1UL<<size_shift;
319 return ((u/2 + u) >= size) ? true : false;
323 shrink_check(xhash_t *xhash)
325 xhashidx size_shift = xhash->size_shift;
326 xhashidx size = (xhashidx)1<<size_shift;
327 xhashidx u = xhash->used;
328 return (4*u < size && size_shift > xhash->minsize_shift) ? true : false;
337 xhash_get_alloc_size(xhashidx size_shift)
339 return get_alloc_size(size_shift, true);
343 xhash_new(xhashidx minsize_shift, enum xhash_type type)
345 return xhash_new__(minsize_shift, minsize_shift, type, true);
348 void xhash_free(struct xhash *xhash)
353 void xhash_init(struct xhash *xhash, xhashidx minsize_shift, enum xhash_type type)
355 xhash_init__(xhash, minsize_shift, minsize_shift, type, true);
360 xhash_grow(struct xhash *xhash)
362 xhashidx new_size_shift = xhash_grow_size_shift(xhash);
363 return xhash_resize(xhash, new_size_shift);
367 xhash_shrink(struct xhash *xhash)
369 xhashidx new_size_shift = xhash_shrink_size_shift(xhash);
370 return xhash_resize(xhash, new_size_shift);
373 static inline xhash_t*
374 xhash_grow_check(xhash_t *xhash)
376 if (grow_check(xhash))
377 return xhash_grow(xhash);
383 #define PHASH_UPDATE(xhash, key, val, vals_flag) \
385 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun; \
386 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun; \
387 xhashidx size = 1UL<<(xhash->size_shift); \
388 xhashidx perturb = key; \
389 xhashidx mask = size-1; \
390 xhashidx idx = hash_fun(key) & mask; \
391 xhashidx *kvs = xhash_kvs(xhash); \
393 INCSTAT(xhash->inserts); \
395 if ( !item_valid(xhash, idx, vals_flag) ){ \
396 PHUPD_SET__(xhash, idx, key, val); \
399 if (cmp_fun(kvs[idx], key)){ \
400 PHUPD_UPDATE__(xhash, idx, key, val); \
404 again: __attribute__((unused)) \
405 INCSTAT(xhash->bounces); \
406 idx = ((idx<<2) + idx + 1 + perturb) & mask; \
407 perturb >>= PERTURB_SHIFT; \
412 set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
414 xhashidx *kvs = xhash_kvs(p);
415 xhashidx *vals = xhash_vals(p);
420 void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
422 xhashidx *kvs = xhash_kvs(p);
423 xhashidx *vals = xhash_vals(p);
424 if (item_dummy(p, idx, true))
432 inc_val(xhash_t *p, xhashidx idx, xhashidx val)
434 xhashidx *vals = xhash_vals(p);
438 void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
440 //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
441 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
442 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
443 PHASH_UPDATE(xhash, key, val, true)
444 #undef PHUPD_UPDATE__
448 int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
450 if (grow_check(xhash))
451 return -XHASH_ERESIZE;
452 xhash_insert__(xhash, key, val);
457 void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
459 #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
460 #define PHUPD_SET__(_p, _i, _k, _v) xhash_upd_set(_p, _i, _k, _v)
461 PHASH_UPDATE(xhash, key, val, true)
462 #undef PHUPD_UPDATE__
466 int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
468 if (grow_check(xhash))
469 return -XHASH_ERESIZE;
470 xhash_freql_update__(xhash, key, val);
475 xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhash_t *new)
480 new = xhash_new__(new_size_shift, xhash->minsize_shift, xhash->type, true);
482 xhash_init__(new, new_size_shift, xhash->minsize_shift, xhash->type, true);
487 //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
488 for (i = 0; i < xhash_size(xhash); i++) {
489 if (item_valid(xhash, i, true)){
490 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
491 xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
501 * note that his function does not modify the internal structure of the hash
502 * and thus its safe to use it for updating values during a xhash_iterate()
504 int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
506 //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
507 #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
508 #define PHUPD_SET__(_p, _i, _k, _v) goto again
509 PHASH_UPDATE(xhash, key, val, true)
510 #undef PHUPD_UPDATE__
517 int xhash_delete(struct xhash *xhash, xhashidx key)
519 if (shrink_check(xhash))
520 return -XHASH_ERESIZE;
521 return xhash_delete__(xhash, key, true);
524 int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
526 xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
527 xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;
528 xhashidx size_shift = xhash->size_shift;
529 xhashidx size = (xhashidx)1<<size_shift;
530 xhashidx perturb = key;
531 xhashidx mask = size-1;
532 xhashidx idx = hash_fun(key) & mask;
533 xhashidx *kvs = xhash_kvs(xhash);
535 INCSTAT(xhash->lookups);
537 if ( item_unused(xhash, idx, vals) )
538 return -XHASH_EEXIST;
540 if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
545 INCSTAT(xhash->bounces);
546 idx = ((idx<<2) + idx + 1 + perturb) & mask;
547 perturb >>= PERTURB_SHIFT;
551 int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
554 int ret = xhash_lookup__(xhash, key, &idx, true);
556 xhashidx *values = xhash_vals(xhash);
562 //FIXME iteration broken
564 xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
566 pi->cnt = pi->loc = 0;
570 xhash_iterate__(xhash_t *xhash, bool vals,
571 xhash_iter_t *pi, xhashidx *key_ret, xhashidx *idx_ret)
573 xhashidx idx = pi->loc;
574 xhashidx size = (xhashidx)1<<xhash->size_shift;
575 xhashidx *kvs = xhash_kvs(xhash);
576 INCSTAT(xhash->lookups);
578 if (xhash->used == pi->cnt || idx >= size)
581 if (item_valid(xhash, idx, vals)){
593 int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
596 int ret = xhash_iterate__(xhash, true, pi, key, &idx);
598 xhashidx *vals = xhash_vals(xhash);
604 void xhash_print(xhash_t *xhash)
610 xhash_iter_init(xhash, &pi);
611 XSEGLOG("PHASH(%p):\n", xhash);
613 ret = xhash_iterate(xhash, &pi, &key, &val);
617 XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
627 " insert : I <key> <val> \n"
628 " update : U <key> <val> (->v += val if exists) \n"
630 " delete : D <key> \n"
635 int main(int argc, char **argv)
638 char *s, buf[BUFLEN];
642 ph = xhash_new(2, INTEGER);
645 s = fgets(buf, BUFLEN-1, stdin);
652 ret = sscanf(s+1, "%lu %lu", &key, &val);
654 xhash_insert(ph, key, val);
659 ret = sscanf(s+1, "%lu %lu", &key, &val);
661 xhash_freql_update(ph, key, val);
666 ret = sscanf(s+1, "%lu", &key);
668 ret = xhash_lookup(ph, key, &val);
670 printf("%lu\n", val);
678 ret = sscanf(s+1, "%lu", &key);
680 xhash_delete(ph, key);
685 printf("%lu\n", xhash_elements(ph));
713 pset_new(xhashidx minsize_shift)
716 pset = malloc(sizeof(pset_t));
721 xhash_init__(&pset->ph_, minsize_shift, false);
726 pset_init(pset_t *pset, xhashidx minsize_shift)
728 xhash_init__(&pset->ph_, minsize_shift, false);
732 pset_free(pset_t *pset)
734 xhash_tfree(&pset->ph_);
739 pset_tfree(pset_t *pset)
741 xhash_tfree(&pset->ph_);
745 pset_resize(pset_t *pset, xhashidx new_size_shift)
748 xhash_cp(&(old.ph_), &pset->ph_);
750 xhash_resize__(&pset->ph_, new_size_shift, false);
751 for (xhashidx i = 0; i < pset_size(&old); i++) {
752 if (item_valid(&(old.ph_), i, false)){
753 //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
754 pset_insert(pset, old.ph_.kvs[i]);
761 pset_grow(pset_t *pset)
763 xhashidx new_size_shift = grow_size_shift(&pset->ph_);
764 pset_resize(pset, new_size_shift);
768 pset_grow_check(pset_t *pset)
770 if (grow_check(&pset->ph_))
774 void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
776 if (item_dummy(p, idx, false))
782 void pset_insert(pset_t *pset, xhashidx key)
784 xhash_t *ph = &pset->ph_;
786 pset_grow_check(pset);
787 #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
788 #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
789 PHASH_UPDATE(ph, key, 0xdeadbabe, false)
790 #undef PHUPD_UPDATE__
795 pset_shrink(pset_t *pset)
797 xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
798 pset_resize(pset, new_size_shift);
801 int pset_delete(pset_t *pset, xhashidx key)
803 if (pset->ph_.used == 0)
807 xhashidx size_shift = pset->ph_.size_shift;
808 xhashidx size = (xhashidx)1<<size_shift;
809 xhashidx u = pset->ph_.used;
812 return xhash_delete__(&pset->ph_, key, false);
815 bool pset_lookup(pset_t *pset, xhashidx key)
818 return !!xhash_lookup__(&pset->ph_, key, &idx, false);
821 int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
824 int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
828 void pset_print(pset_t *pset)
834 pset_iter_init(pset, &pi);
835 printf("PSET(%p):\n", pset);
837 ret = pset_iterate(pset, &pi, &key);
841 printf(" 0x%017lx\n", key);
846 #if defined(PSET_MAIN)
851 " insert : I <key> <val> \n"
853 " delete : D <key> \n"
858 int main(int argc, char **argv)
861 char *s, buf[BUFLEN];
868 s = fgets(buf, BUFLEN-1, stdin);
875 ret = sscanf(s+1, "%lu", &key);
877 pset_insert(ps, key);
882 ret = sscanf(s+1, "%lu", &key);
884 ret = pset_lookup(ps, key);
885 printf("%lu -> %s\n", key, ret ? "true" : "false");
890 ret = sscanf(s+1, "%lu", &key);
892 pset_delete(ps, key);
897 printf("%lu\n", pset_elements(ps));
923 #include <linux/module.h>
924 #include <xtypes/xhash_exports.h>
927 // vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4