1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
/*
* BIRD Library -- Generic Hash Table
*
* (c) 2013 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2013 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_HASH_H_
#define _BIRD_HASH_H_
#define HASH(type) struct { type **data; uint count, order; }
#define HASH_TYPE(v) typeof(** (v).data)
#define HASH_SIZE(v) (1U << (v).order)
#define HASH_EQ(v,id,k1,k2...) (id##_EQ(k1, k2))
#define HASH_FN(v,id,key...) ((u32) (id##_FN(key)) >> (32 - (v).order))
#define HASH_INIT(v,pool,init_order) \
({ \
(v).count = 0; \
(v).order = (init_order); \
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
})
#define HASH_FREE(v) \
({ \
mb_free((v).data); \
(v) = (typeof(v)){ }; \
})
#define HASH_FIND(v,id,key...) \
({ \
u32 _h = HASH_FN(v, id, key); \
HASH_TYPE(v) *_n = (v).data[_h]; \
while (_n && !HASH_EQ(v, id, id##_KEY(_n), key)) \
_n = id##_NEXT(_n); \
_n; \
})
#define HASH_INSERT(v,id,node) \
({ \
u32 _h = HASH_FN(v, id, id##_KEY((node))); \
HASH_TYPE(v) **_nn = (v).data + _h; \
id##_NEXT(node) = *_nn; \
*_nn = node; \
(v).count++; \
})
#define HASH_DO_REMOVE(v,id,_nn) \
({ \
*_nn = id##_NEXT((*_nn)); \
(v).count--; \
})
#define HASH_DELETE(v,id,key...) \
({ \
u32 _h = HASH_FN(v, id, key); \
HASH_TYPE(v) *_n, **_nn = (v).data + _h; \
\
while ((*_nn) && !HASH_EQ(v, id, id##_KEY((*_nn)), key)) \
_nn = &(id##_NEXT((*_nn))); \
\
if (_n = *_nn) \
HASH_DO_REMOVE(v,id,_nn); \
_n; \
})
#define HASH_REMOVE(v,id,node) \
({ \
u32 _h = HASH_FN(v, id, id##_KEY((node))); \
HASH_TYPE(v) *_n, **_nn = (v).data + _h; \
\
while ((*_nn) && (*_nn != (node))) \
_nn = &(id##_NEXT((*_nn))); \
\
if (_n = *_nn) \
HASH_DO_REMOVE(v,id,_nn); \
_n; \
})
#define HASH_REHASH(v,id,pool,step) \
({ \
HASH_TYPE(v) *_n, *_n2, **_od; \
uint _i, _os; \
\
_os = HASH_SIZE(v); \
_od = (v).data; \
(v).count = 0; \
(v).order += (step); \
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
\
for (_i = 0; _i < _os; _i++) \
for (_n = _od[_i]; _n && (_n2 = id##_NEXT(_n), 1); _n = _n2) \
HASH_INSERT(v, id, _n); \
\
mb_free(_od); \
})
#define REHASH_LO_MARK(a,b,c,d,e,f) a
#define REHASH_HI_MARK(a,b,c,d,e,f) b
#define REHASH_LO_STEP(a,b,c,d,e,f) c
#define REHASH_HI_STEP(a,b,c,d,e,f) d
#define REHASH_LO_BOUND(a,b,c,d,e,f) e
#define REHASH_HI_BOUND(a,b,c,d,e,f) f
#define HASH_DEFINE_REHASH_FN(id,type) \
static void id##_REHASH(void *v, pool *p, int step) \
{ HASH_REHASH(* (HASH(type) *) v, id, p, step); }
#define HASH_MAY_STEP_UP(v,id,pool) HASH_MAY_STEP_UP_(v,pool, id##_REHASH, id##_PARAMS)
#define HASH_MAY_STEP_DOWN(v,id,pool) HASH_MAY_STEP_DOWN_(v,pool, id##_REHASH, id##_PARAMS)
#define HASH_MAY_RESIZE_DOWN(v,id,pool) HASH_MAY_RESIZE_DOWN_(v,pool, id##_REHASH, id##_PARAMS)
#define HASH_MAY_STEP_UP_(v,pool,rehash_fn,args) \
({ \
if (((v).count > (HASH_SIZE(v) REHASH_HI_MARK(args))) && \
((v).order < (REHASH_HI_BOUND(args)))) \
rehash_fn(&(v), pool, REHASH_HI_STEP(args)); \
})
#define HASH_MAY_STEP_DOWN_(v,pool,rehash_fn,args) \
({ \
if (((v).count < (HASH_SIZE(v) REHASH_LO_MARK(args))) && \
((v).order > (REHASH_LO_BOUND(args)))) \
rehash_fn(&(v), pool, -(REHASH_LO_STEP(args))); \
})
#define HASH_MAY_RESIZE_DOWN_(v,pool,rehash_fn,args) \
({ \
uint _o = (v).order; \
while (((v).count < ((1U << _o) REHASH_LO_MARK(args))) && \
(_o > (REHASH_LO_BOUND(args)))) \
_o -= (REHASH_LO_STEP(args)); \
if (_o < (v).order) \
rehash_fn(&(v), pool, _o - (v).order); \
})
#define HASH_INSERT2(v,id,pool,node) \
({ \
HASH_INSERT(v, id, node); \
HASH_MAY_STEP_UP(v, id, pool); \
})
#define HASH_DELETE2(v,id,pool,key...) \
({ \
HASH_TYPE(v) *_n = HASH_DELETE(v, id, key); \
if (_n) HASH_MAY_STEP_DOWN(v, id, pool); \
_n; \
})
#define HASH_REMOVE2(v,id,pool,node) \
({ \
HASH_TYPE(v) *_n = HASH_REMOVE(v, id, node); \
if (_n) HASH_MAY_STEP_DOWN(v, id, pool); \
_n; \
})
#define HASH_WALK(v,next,n) \
do { \
HASH_TYPE(v) *n; \
uint _i; \
uint _s = HASH_SIZE(v); \
for (_i = 0; _i < _s; _i++) \
for (n = (v).data[_i]; n; n = n->next)
#define HASH_WALK_END } while (0)
#define HASH_WALK_DELSAFE(v,next,n) \
do { \
HASH_TYPE(v) *n, *_next; \
uint _i; \
uint _s = HASH_SIZE(v); \
for (_i = 0; _i < _s; _i++) \
for (n = (v).data[_i]; n && (_next = n->next, 1); n = _next)
#define HASH_WALK_DELSAFE_END } while (0)
#define HASH_WALK_FILTER(v,next,n,nn) \
do { \
HASH_TYPE(v) *n, **nn; \
uint _i; \
uint _s = HASH_SIZE(v); \
for (_i = 0; _i < _s; _i++) \
for (nn = (v).data + _i; n = *nn; (*nn == n) ? (nn = &n->next) : NULL)
#define HASH_WALK_FILTER_END } while (0)
static inline void
mem_hash_init(u64 *h)
{
*h = 0x001047d54778bcafULL;
}
static inline void
mem_hash_mix(u64 *h, const void *p, uint s)
{
const u64 multiplier = 0xb38bc09a61202731ULL;
const char *pp = p;
uint i;
for (i=0; i<s/4; i++)
*h = *h * multiplier + ((const u32 *)pp)[i];
for (i=s & ~0x3; i<s; i++)
*h = *h * multiplier + pp[i];
}
static inline void
mem_hash_mix_num(u64 *h, u64 val)
{
mem_hash_mix(h, &val, sizeof(val));
}
static inline uint
mem_hash_value(u64 *h)
{
return ((*h >> 32) ^ (*h & 0xffffffff));
}
static inline uint
mem_hash(const void *p, uint s)
{
static u64 h;
mem_hash_init(&h);
mem_hash_mix(&h, p, s);
return mem_hash_value(&h);
}
static inline uint
ptr_hash(void *ptr)
{
uintptr_t p = (uintptr_t) ptr;
return p ^ (p << 8) ^ (p >> 16);
}
#endif
|