#ifndef HSHTB_H_ #define HSHTB_H_ #include #include #include #include "hal/hal.h" #include "util/util.h" #define HSHTB_FNV32_OFF 0x811c9dc5u #define HSHTB_FNV32_PRIME 0x01000193u static inline uint32_t hshtb_fnv32(const void *data, size_t len) { const unsigned char *p = (const unsigned char *)data; uint32_t h = HSHTB_FNV32_OFF; for (size_t i = 0; i < len; i++) { h ^= p[i]; h *= HSHTB_FNV32_PRIME; } return h; } enum { HSHTB_EMPTY = 0, HSHTB_TAKEN = 1, HSHTB_TOMB = 2, }; #define HSHTB_ALLOC(tb, keyfield, k, out) \ do { \ size_t __len = sizeof((tb)) / sizeof((tb)[0]); \ uint32_t __h = hshtb_fnv32((k), hal_strlen((k))); \ size_t __idx = __h % __len; \ size_t __start = __idx; \ typeof(&(tb)[0]) __tomb = NULL; \ do { \ if ((tb)[__idx]._hshtbstate == HSHTB_EMPTY) { \ typeof(&(tb)[0]) __slot = __tomb ? __tomb : &(tb)[__idx]; \ hal_memset(__slot, 0, sizeof(*__slot)); \ __slot->_hshtbstate = HSHTB_TAKEN; \ hal_memcpy(__slot->keyfield, (k), MIN(sizeof(__slot->keyfield) - 1, hal_strlen((k)))); \ (out) = __slot; \ break; \ } \ if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && hal_strcmp((tb)[__idx].keyfield, (k)) == 0) { \ (out) = &(tb)[__idx]; \ break; \ } \ if ((tb)[__idx]._hshtbstate == HSHTB_TOMB && !__tomb) { \ __tomb = &(tb)[__idx]; \ } \ __idx = (__idx + 1) % __len; \ } while(__idx != __start); \ } while(0) #define HSHTB_GET(tb, keyfield, k, out) \ do { \ size_t __len = sizeof((tb)) / sizeof((tb)[0]); \ uint32_t __h = hshtb_fnv32((k), hal_strlen((k))); \ size_t __idx = __h % __len; \ size_t __start = __idx; \ (out) = NULL; \ do { \ if ((tb)[__idx]._hshtbstate == HSHTB_EMPTY) { \ break; \ } \ if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && hal_strcmp((tb)[__idx].keyfield, (k)) == 0) { \ (out) = &(tb)[__idx]; \ break; \ } \ __idx = (__idx + 1) % __len; \ } while(__idx != __start); \ } while(0) #define HSHTB_DELETE(tb, keyfield, k) \ do { \ typeof(&(tb)[0]) __e; \ HSHTB_GET((tb), (keyfield), (k), __e); \ if (__e) { \ __e->state = HSHTB_TOMB; \ } \ } while(0) #endif // HSHTB_H_