89 lines
2.4 KiB
C
89 lines
2.4 KiB
C
#ifndef HSHTB_H_
|
|
#define HSHTB_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#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_ARRAY_LEN(tb) \
|
|
((void)sizeof(struct { int _[!!(sizeof(tb) % sizeof((tb)[0]) == 0)]; }) , (sizeof(tb) / sizeof((tb)[0])))
|
|
|
|
#define HSHTB_ALLOC(tb, keyfield, k, out) \
|
|
do { \
|
|
size_t __len = __HSHTB_ARRAY_LEN(tb); \
|
|
uint32_t __h = hshtb_fnv32((k), hal_strlen((k))); \
|
|
size_t __idx = __h % __len; \
|
|
size_t __start = __idx; \
|
|
typeof(&(tb)[0]) __tomb = NULL; \
|
|
(out) = 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 = __HSHTB_ARRAY_LEN(tb); \
|
|
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->_hshtbstate = HSHTB_TOMB; \
|
|
} \
|
|
} while(0)
|
|
|
|
#endif // HSHTB_H_
|