Annotation of embedaddon/bird2/lib/hash.h, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>