modified: src1/input.c
[GalaxyCodeBases.git] / c_cpp / lib / klib / cpp / khash.hpp
bloba57d6de7f68e93cbb738adbbe2eddbab32cca400
1 #ifndef KHASH_HPP
2 #define KHASH_HPP
4 #include <memory>
5 #include <functional>
6 #include <cstdlib> // for malloc() etc
7 #include <cstring> // for memset()
9 #include <stdint.h> // for uint32_t
11 namespace klib {
13 #ifndef kroundup32 // FIXME: doesn't work for 64-bit integers
14 #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
15 #endif
17 #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
18 #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
19 #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
20 #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
21 #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
22 #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
23 #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
24 #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
25 #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
27 #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
29 template<class T, class Hash, class Eq = std::equal_to<T>, typename khint_t = uint32_t>
30 class KHash {
31 khint_t n_buckets, count, n_occupied, upper_bound;
32 uint32_t *flags;
33 T *keys;
34 public:
35 KHash() : n_buckets(0), count(0), n_occupied(0), upper_bound(0), flags(NULL), keys(NULL) {};
36 ~KHash() { std::free(flags); std::free(keys); };
37 khint_t capacity(void) const { return n_buckets; };
38 khint_t size(void) const { return count; };
39 khint_t begin(void) const { return 0; };
40 khint_t end(void) const { return n_buckets; };
42 void exist(khint_t x) const { return !__ac_iseither(flags, x); };
43 T &at(khint_t x) { return keys[x]; };
45 khint_t get(const T &key) const {
46 if (n_buckets) {
47 khint_t k, i, last, mask, step = 0;
48 mask = n_buckets - 1;
49 k = Hash()(key); i = k & mask;
50 last = i;
51 while (!__ac_isempty(flags, i) && (__ac_isdel(flags, i) || !Eq()(keys[i], key))) {
52 i = (i + (++step)) & mask;
53 if (i == last) return n_buckets;
55 return __ac_iseither(flags, i)? n_buckets : i;
56 } else return 0;
59 int resize(khint_t new_n_buckets) {
60 uint32_t *new_flags = 0;
61 khint_t j = 1;
63 kroundup32(new_n_buckets);
64 if (new_n_buckets < 4) new_n_buckets = 4;
65 if (count >= (new_n_buckets>>1) + (new_n_buckets>>2)) j = 0; /* requested count is too small */
66 else { /* hash table count to be changed (shrink or expand); rehash */
67 new_flags = (uint32_t*)std::malloc(__ac_fsize(new_n_buckets) * sizeof(uint32_t));
68 if (!new_flags) return -1;
69 ::memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(uint32_t));
70 if (n_buckets < new_n_buckets) { /* expand */
71 T *new_keys = (T*)std::realloc((void *)keys, new_n_buckets * sizeof(T));
72 if (!new_keys) { std::free(new_flags); return -1; }
73 keys = new_keys;
74 } /* otherwise shrink */
77 if (j) { /* rehashing is needed */
78 for (j = 0; j != n_buckets; ++j) {
79 if (__ac_iseither(flags, j) == 0) {
80 T key = keys[j];
81 khint_t new_mask;
82 new_mask = new_n_buckets - 1;
83 __ac_set_isdel_true(flags, j);
84 while (1) { /* kick-out process; sort of like in Cuckoo hashing */
85 khint_t k, i, step = 0;
86 k = Hash()(key);
87 i = k & new_mask;
88 while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask;
89 __ac_set_isempty_false(new_flags, i);
90 if (i < n_buckets && __ac_iseither(flags, i) == 0) { /* kick out the existing element */
91 { T tmp = keys[i]; keys[i] = key; key = tmp; }
92 __ac_set_isdel_true(flags, i); /* mark it as deleted in the old hash table */
93 } else { /* write the element and jump out of the loop */
94 keys[i] = key;
95 break;
100 if (n_buckets > new_n_buckets) /* shrink the hash table */
101 keys = (T*)std::realloc((void *)keys, new_n_buckets * sizeof(T));
102 std::free(flags); /* free the working space */
103 flags = new_flags;
104 n_buckets = new_n_buckets;
105 n_occupied = count;
106 upper_bound = (n_buckets>>1) + (n_buckets>>2);
108 return 0;
111 khint_t put(const T &key, int *ret) {
112 khint_t x;
113 if (n_occupied >= upper_bound) { /* update the hash table */
114 if (n_buckets > (count<<1)) {
115 if (resize(n_buckets - 1) < 0) { /* clear "deleted" elements */
116 *ret = -1; return n_buckets;
118 } else if (resize(n_buckets + 1) < 0) { /* expand the hash table */
119 *ret = -1; return n_buckets;
121 } /* TODO: to implement automatically shrinking; resize() already support shrinking */
123 khint_t k, i, site, last, mask = n_buckets - 1, step = 0;
124 x = site = n_buckets; k = Hash()(key); i = k & mask;
125 if (__ac_isempty(flags, i)) x = i; /* for speed up */
126 else {
127 last = i;
128 while (!__ac_isempty(flags, i) && (__ac_isdel(flags, i) || !Eq()(keys[i], key))) {
129 if (__ac_isdel(flags, i)) site = i;
130 i = (i + (++step)) & mask;
131 if (i == last) { x = site; break; }
133 if (x == n_buckets) {
134 if (__ac_isempty(flags, i) && site != n_buckets) x = site;
135 else x = i;
139 if (__ac_isempty(flags, x)) { /* not present at all */
140 keys[x] = key;
141 __ac_set_isboth_false(flags, x);
142 ++count; ++n_occupied;
143 *ret = 1;
144 } else if (__ac_isdel(flags, x)) { /* deleted */
145 keys[x] = key;
146 __ac_set_isboth_false(flags, x);
147 ++count;
148 *ret = 2;
149 } else *ret = 0; /* Don't touch keys[x] if present and not deleted */
150 return x;
153 void del(khint_t x) {
154 if (x != n_buckets && !__ac_iseither(flags, x)) {
155 __ac_set_isdel_true(flags, x);
156 --count;
161 } // end of namespace klib
163 #endif