#ifndef __CACHELIB_HASHTABLE_H__
#define __CACHELIB_HASHTABLE_H__
#include <string.h>
#define HASHTABLE_INITIAL_ENTRIES_CAPACITY 8
typedef unsigned int hashtable_index_t;
#define HASHTABLE_ENTRY_HEAD(name, type) struct name { \
type *values; \
size_t capacity; \
size_t size; \
}
#define HASHTABLE_HEAD(name, entry) struct name { \
struct entry *entries; \
size_t entries_size; \
}
#define HASHTABLE_ENTRIES_COUNT(table) \
((table)->entries_size)
#define HASHTABLE_INIT(table, type, field, _entries_size) \
do { \
hashtable_index_t var; \
(table)->entries = calloc(_entries_size, \
sizeof(*(table)->entries)); \
(table)->entries_size = (_entries_size); \
for (var = 0; var < HASHTABLE_ENTRIES_COUNT(table); ++var) {\
(table)->entries[var].field.capacity = \
HASHTABLE_INITIAL_ENTRIES_CAPACITY; \
(table)->entries[var].field.size = 0; \
(table)->entries[var].field.values = malloc( \
sizeof(type) * \
HASHTABLE_INITIAL_ENTRIES_CAPACITY); \
assert((table)->entries[var].field.values != NULL);\
} \
} while (0)
#define HASHTABLE_DESTROY(table, field) \
do { \
hashtable_index_t var; \
for (var = 0; var < HASHTABLE_ENTRIES_COUNT(table); ++var) {\
free((table)->entries[var].field.values); \
} \
} while (0)
#define HASHTABLE_GET_ENTRY(table, hash) \
(&((table)->entries[hash]))
#define HASHTABLE_FOREACH(table, var) \
for ((var) = &((table)->entries[0]); \
(var) < &((table)->entries[HASHTABLE_ENTRIES_COUNT(table)]);\
++(var))
#define HASHTABLE_ENTRY_FOREACH(entry, field, var) \
for ((var) = &((entry)->field.values[0]); \
(var) < &((entry)->field.values[(entry)->field.size]); \
++(var))
#define HASHTABLE_ENTRY_CLEAR(entry, field) \
((entry)->field.size = 0)
#define HASHTABLE_ENTRY_SIZE(entry, field) \
((entry)->field.size)
#define HASHTABLE_ENTRY_CAPACITY(entry, field) \
((entry)->field.capacity)
#define HASHTABLE_ENTRY_CAPACITY_INCREASE(entry, field, type) \
do { \
(entry)->field.capacity *= 2; \
(entry)->field.values = realloc((entry)->field.values, \
(entry)->field.capacity * sizeof(type)); \
} while (0)
#define HASHTABLE_ENTRY_CAPACITY_DECREASE(entry, field, type) \
do { \
(entry)->field.capacity /= 2; \
(entry)->field.values = realloc((entry)->field.values, \
(entry)->field.capacity * sizeof(type)); \
} while (0)
#define HASHTABLE_PROTOTYPE(name, entry_, type) \
hashtable_index_t name##_CALCULATE_HASH(struct name *, type *); \
void name##_ENTRY_STORE(struct entry_*, type *); \
type *name##_ENTRY_FIND(struct entry_*, type *); \
type *name##_ENTRY_FIND_SPECIAL(struct entry_ *, type *, \
int (*) (const void *, const void *)); \
void name##_ENTRY_REMOVE(struct entry_*, type *);
#define HASHTABLE_GENERATE(name, entry_, type, field, HASH, CMP) \
hashtable_index_t name##_CALCULATE_HASH(struct name *table, type *data) \
{ \
\
return HASH(data, table->entries_size); \
} \
\
void name##_ENTRY_STORE(struct entry_ *the_entry, type *data) \
{ \
\
if (the_entry->field.size == the_entry->field.capacity) \
HASHTABLE_ENTRY_CAPACITY_INCREASE(the_entry, field, type);\
\
memcpy(&(the_entry->field.values[the_entry->field.size++]), \
data, \
sizeof(type)); \
qsort(the_entry->field.values, the_entry->field.size, \
sizeof(type), CMP); \
} \
\
type *name##_ENTRY_FIND(struct entry_ *the_entry, type *key) \
{ \
\
return ((type *)bsearch(key, the_entry->field.values, \
the_entry->field.size, sizeof(type), CMP)); \
} \
\
type *name##_ENTRY_FIND_SPECIAL(struct entry_ *the_entry, type *key, \
int (*compar) (const void *, const void *)) \
{ \
return ((type *)bsearch(key, the_entry->field.values, \
the_entry->field.size, sizeof(type), compar)); \
} \
\
void name##_ENTRY_REMOVE(struct entry_ *the_entry, type *del_elm) \
{ \
\
memmove(del_elm, del_elm + 1, \
(&the_entry->field.values[--the_entry->field.size] - del_elm) *\
sizeof(type)); \
}
#define HASHTABLE_CALCULATE_HASH(name, table, data) \
(name##_CALCULATE_HASH((table), data))
#define HASHTABLE_ENTRY_STORE(name, entry, data) \
name##_ENTRY_STORE((entry), data)
#define HASHTABLE_ENTRY_FIND(name, entry, key) \
(name##_ENTRY_FIND((entry), (key)))
#define HASHTABLE_ENTRY_FIND_SPECIAL(name, entry, key, cmp) \
(name##_ENTRY_FIND_SPECIAL((entry), (key), (cmp)))
#define HASHTABLE_ENTRY_REMOVE(name, entry, del_elm) \
name##_ENTRY_REMOVE((entry), (del_elm))
#endif