Vinicius Teshima 1 жил өмнө
parent
commit
523e7daa9f
1 өөрчлөгдсөн 192 нэмэгдсэн , 0 устгасан
  1. 192 0
      src/ht.h

+ 192 - 0
src/ht.h

@@ -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