|
@@ -0,0 +1,192 @@
|
|
|
|
|
+#ifndef HT_H
|
|
|
|
|
+#define HT_H
|
|
|
|
|
+
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+#include <stddef.h>
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+#include <string.h>
|
|
|
|
|
+
|
|
|
|
|
+#ifndef typeof
|
|
|
|
|
+#define typeof __typeof__
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+#define CONCAT(a, b) CONCAT_INNER(a, b)
|
|
|
|
|
+#define CONCAT_INNER(a, b) a ## b
|
|
|
|
|
+#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)
|
|
|
|
|
+
|
|
|
|
|
+typedef uint64_t (*ht_hash_func)(const char *, size_t);
|
|
|
|
|
+
|
|
|
|
|
+uint64_t ht_default_hash(const char *str, size_t str_size);
|
|
|
|
|
+
|
|
|
|
|
+#define HT_DEF_STRUCT(type, name) \
|
|
|
|
|
+ struct name##_item { \
|
|
|
|
|
+ struct { \
|
|
|
|
|
+ const char *data; \
|
|
|
|
|
+ size_t size; \
|
|
|
|
|
+ } key_str; \
|
|
|
|
|
+ uint64_t key; \
|
|
|
|
|
+ type data; \
|
|
|
|
|
+ void *next; \
|
|
|
|
|
+ }; \
|
|
|
|
|
+ struct name { \
|
|
|
|
|
+ struct name##_item *items; \
|
|
|
|
|
+ size_t size; \
|
|
|
|
|
+ size_t cap; \
|
|
|
|
|
+ ht_hash_func hash; \
|
|
|
|
|
+ size_t collisions; \
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+#define HT_DEF_STRUCT_ITEM(type, name) \
|
|
|
|
|
+ struct { \
|
|
|
|
|
+ struct { \
|
|
|
|
|
+ uint64_t key; \
|
|
|
|
|
+ type data; \
|
|
|
|
|
+ void *next; \
|
|
|
|
|
+ } *items; \
|
|
|
|
|
+ size_t size; \
|
|
|
|
|
+ size_t cap; \
|
|
|
|
|
+ ht_hash_func hash; \
|
|
|
|
|
+ } name
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define HT_CREATE(ht, init_cap) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ (ht).cap = (init_cap); \
|
|
|
|
|
+ (ht).size = 0; \
|
|
|
|
|
+ (ht).items = calloc((ht).cap, sizeof(*(ht).items)); \
|
|
|
|
|
+ (ht).hash = ht_default_hash; \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
|
|
+#define _HT_DESTROY(ht, _t, _hi) \
|
|
|
|
|
+ do{ \
|
|
|
|
|
+ void *_t = NULL; \
|
|
|
|
|
+ for ( i = 0; i < (ht).cap; ++i ) { \
|
|
|
|
|
+ typeof(*(ht).items) *_hi = &(ht).items[i]; \
|
|
|
|
|
+ while( _hi->next != NULL ) { \
|
|
|
|
|
+ _t = _hi; \
|
|
|
|
|
+ _hi = _hi->next; \
|
|
|
|
|
+ free(_t); \
|
|
|
|
|
+ } \
|
|
|
|
|
+ } \
|
|
|
|
|
+ free((ht).items); \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
|
|
+#define HT_DESTROY(ht) \
|
|
|
|
|
+ _HT_DESTROY(ht, UNIQUE_NAME(_t), UNIQUE_NAME(_hi))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define _HT_INC_CAP(ht, _ht, _it) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ typeof((ht)) _ht = {0}; \
|
|
|
|
|
+ HT_CREATE(_ht, (ht).cap*2); \
|
|
|
|
|
+ for ( i = 0; i < (ht).cap; ++i ) { \
|
|
|
|
|
+ typeof(*(ht).items) _hi = (ht).items[i]; \
|
|
|
|
|
+ typeof(*(_ht).items) *_it = &_ht.items[_hi.key \
|
|
|
|
|
+ % _ht.cap]; \
|
|
|
|
|
+ if ( _it->key != 0 && _it->key != _hi.key ) { \
|
|
|
|
|
+ while( _it->next != NULL ) { \
|
|
|
|
|
+ _it = _it->next; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ _it->next = malloc(sizeof(*(_ht).items)); \
|
|
|
|
|
+ _it = _it->next; \
|
|
|
|
|
+ ++(ht).collisions; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ if ( _it->key == _hi.key ) { \
|
|
|
|
|
+ _it->data = _hi.data; \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ _it->key_str.data = _hi.key_str.data; \
|
|
|
|
|
+ _it->key_str.size = _hi.key_str.size; \
|
|
|
|
|
+ _it->key = _hi.key; \
|
|
|
|
|
+ _it->data = _hi.data; \
|
|
|
|
|
+ _it->next = NULL; \
|
|
|
|
|
+ ++(_ht).size; \
|
|
|
|
|
+ _it->next = _hi.next; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ HT_DESTROY(ht); \
|
|
|
|
|
+ (ht) = _ht; \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
|
|
+#define HT_INC_CAP(ht) \
|
|
|
|
|
+ _HT_INC_CAP(ht, UNIQUE_NAME(_ht), UNIQUE_NAME(_it))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#define _HT_SET(ht, _key, _key_size, val, _k, _it) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ uint64_t _k = (ht).hash((_key), (_key_size)); \
|
|
|
|
|
+ typeof(*(ht).items) *_it = &(ht).items[_k % (ht).cap]; \
|
|
|
|
|
+ if ( _it->key != 0 && _it->key != _k ) { \
|
|
|
|
|
+ while( _it->next != NULL ) { \
|
|
|
|
|
+ _it = _it->next; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ _it->next = malloc(sizeof(*(ht).items)); \
|
|
|
|
|
+ _it = _it->next; \
|
|
|
|
|
+ ++(ht).collisions; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ if ( _it->key == _k ) { \
|
|
|
|
|
+ _it->data = val; \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ _it->key_str.data = _key; \
|
|
|
|
|
+ _it->key_str.size = _key_size; \
|
|
|
|
|
+ _it->key = _k; \
|
|
|
|
|
+ _it->data = val; \
|
|
|
|
|
+ _it->next = NULL; \
|
|
|
|
|
+ ++(ht).size; \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
|
|
+#define HT_SET(ht, key, key_size, val) \
|
|
|
|
|
+ _HT_SET(ht, key, key_size, val, UNIQUE_NAME(_k), UNIQUE_NAME(_it))
|
|
|
|
|
+
|
|
|
|
|
+#define _HT_GET(ht, _key, _key_size, ret, _k, _it) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ uint64_t _k = (ht).hash((_key), (_key_size)); \
|
|
|
|
|
+ typeof(*(ht).items) *_it = &(ht).items[_k % (ht).cap]; \
|
|
|
|
|
+ if ( _it->key != _k ) { \
|
|
|
|
|
+ while( _it->key != _k && _it->next != NULL ) { \
|
|
|
|
|
+ _it = _it->next; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ if ( _it->key != _k ) { \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ } \
|
|
|
|
|
+ (ret) = _it->data; \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
|
|
+#define HT_GET(ht, key, key_size, ret) \
|
|
|
|
|
+ _HT_GET(ht, key, key_size, ret, UNIQUE_NAME(_k), UNIQUE_NAME(_it))
|
|
|
|
|
+
|
|
|
|
|
+#if defined(HT_IMP) || defined(IMP)
|
|
|
|
|
+
|
|
|
|
|
+uint64_t
|
|
|
|
|
+ht_default_hash(const char *str, size_t str_size)
|
|
|
|
|
+{
|
|
|
|
|
+ static uint8_t _primes_list[] = {
|
|
|
|
|
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
|
|
|
|
|
+ 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
|
|
|
|
|
+ 131, 137, 139, 149, 151, 157, 163, 167, 173
|
|
|
|
|
+ };
|
|
|
|
|
+ static uint8_t _primes_list_size = 10;
|
|
|
|
|
+ uint64_t max = UINT64_MAX >> 1;
|
|
|
|
|
+ uint64_t ret = 1;
|
|
|
|
|
+ uint8_t p = 0;
|
|
|
|
|
+ size_t i = 0;
|
|
|
|
|
+ uint8_t b = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for ( i = 0; i < str_size; ++i ) {
|
|
|
|
|
+ b = (uint8_t)str[i];
|
|
|
|
|
+ p = _primes_list[(i + b) % _primes_list_size];
|
|
|
|
|
+ ret = (ret * (b * p)) % max;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#endif /* defined(HT_IMP) || defined(IMP) */
|
|
|
|
|
+
|
|
|
|
|
+#undef CONCAT
|
|
|
|
|
+#undef CONCAT_INNER
|
|
|
|
|
+#undef UNIQUE_NAME
|
|
|
|
|
+
|
|
|
|
|
+#endif
|