+#define hash_define(t, n) \
+ typedef struct hash_ ## t { \
+ t keys[n]; \
+ const void *values[n]; \
+ } hash_ ## t; \
+ static inline uint32_t hash_modulo_ ## t(uint32_t hash) { \
+ return hash & (n - 1); \
+ } \
+ static inline void hash_insert_ ## t (hash_ ##t *hash, const t *key, const void *value) { \
+ uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
+ for(uint8_t f=0; f< (HASH_SEARCH_ITERATIONS - 1); f++){ \
+ if(hash->values[i] == NULL || !memcmp(key, &hash->keys[i], sizeof(t))) { \
+ memcpy(&hash->keys[i], key, sizeof(t)); \
+ hash->values[i] = value; \
+ return; \
+ } \
+ if(++i == n) i = 0; \
+ } \
+ /* We always pick the last slot. It's unfair. But thats life */ \
+ memcpy(&hash->keys[i], key, sizeof(t)); \
+ hash->values[i] = value; \
+ } \
+ static inline void *hash_search_ ## t (const hash_ ##t *hash, const t *key) { \
+ uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
+ for(uint8_t f=0; f<HASH_SEARCH_ITERATIONS; f++){ \
+ if(!memcmp(key, &hash->keys[i], sizeof(t))) { \
+ return (void *)hash->values[i]; \
+ } \
+ if(++i == n) i = 0; \
+ } \
+ return NULL; \
+ } \
+ static inline void hash_delete_ ## t (hash_ ##t *hash, const t *key) { \
+ uint32_t i = hash_modulo_ ## t(hash_function_ ## t(key)); \
+ for(uint8_t f=0; f<HASH_SEARCH_ITERATIONS; f++){ \
+ if(!memcmp(key, &hash->keys[i], sizeof(t))) { \
+ hash->values[i] = NULL; \
+ return; \
+ } \
+ if(++i == n) i = 0; \
+ } \
+ } \
+ static inline void hash_clear_ ## t(hash_ ##t *hash) { \
+ memset(hash->values, 0, n * sizeof(*hash->values)); \
+ memset(hash->keys, 0, n * sizeof(*hash->keys)); \
+ }