From c9c58ca41094738a2eb4eba27992b9cdb6747e0d Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Mon, 6 Mar 2023 12:48:00 +0100 Subject: [PATCH] generic hash map, not used --- text_rendering/generic_hash.h | 156 ++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 text_rendering/generic_hash.h diff --git a/text_rendering/generic_hash.h b/text_rendering/generic_hash.h new file mode 100644 index 0000000..37f8b81 --- /dev/null +++ b/text_rendering/generic_hash.h @@ -0,0 +1,156 @@ +#ifndef _HASH_GENERIC +#define _HASH_GENERIC + +#include +#include + + +#define HASH_MAXSIZE 4096 +// for fibonacci hashing, 2^{32,64}/ +#define HASH_RATIO32 (unsigned int)2654435769u +#define HASH_RATIO64 (unsigned long long int)11400714819322457583u +// salt for string hashing +#define HASH_STRSALT 0xbabb0cac + + +/* Ready-made compares */ +int hash_compare_u32(unsigned int a, unsigned int b) { return a == b; } +int hash_compare_u64(unsigned long long int a, unsigned long long int b) { return a == b; } +int hash_compare_str(const char *a, const char *b) { return strcmp(a, b) == 0; } + + +/* Ready-made hashes */ +unsigned int hash_u64(unsigned long long int c) +{ + return (unsigned long long int)((unsigned long long int)(c*HASH_RATIO64)>>32); +} +unsigned int hash_u32(unsigned int c) +{ + return (unsigned int)((unsigned long long int)(c*HASH_RATIO32)>>32); +} +unsigned int hash_str(const char *s) +{ + unsigned int h = HASH_STRSALT; + const unsigned char *v = (const unsigned char *)(s); + for (int x = *s; x; x--) { + h += v[x-1]; + h += h << 10; + h ^= h >> 6; + } + h += h << 3; + h ^= h >> 11; + h += h << 15; + return h; +} + + +#define HASH_DECL(hashname, codetype, datatype) \ +struct hashname##_entry { \ + codetype code; \ + datatype data; \ +}; \ +\ +struct hashname##_ref { \ + unsigned int items, size; \ + /* Function pointer to hash function */ \ + unsigned int (*hash)(codetype); \ + /* Compare codetype function, return true if equal */ \ + int (*compare)(codetype, codetype); \ + struct hashname##_entry bucket[]; \ +}; \ +\ +\ +struct hashname##_ref * hashname##_create(unsigned int size, unsigned int (*hash)(codetype), int (*compare)(codetype, codetype)) \ +{ \ + if (!size || size > HASH_MAXSIZE) \ + return NULL; \ + if (!hash || !compare) \ + return NULL; \ + /* round to the greater power of two */ \ + /* FIXME: check for intger overflow here */ \ + size = 1<<__builtin_clz(size); \ + /* FIXME: check for intger overflow here */ \ + struct hashname##_ref *h = malloc(sizeof(struct hashname##_ref)+sizeof(struct hashname##_entry)*size); \ + if (h) { \ + h->items = 0; \ + h->size = size; \ + h->hash = hash; \ + h->compare = compare; \ + memset(h->bucket, 0, sizeof(struct hashname##_ref)*size); \ + } \ + return h; \ +} \ +\ +\ +void hashname##_destroy(struct hashname##_ref *hm) \ +{ \ + if (hm) \ + free(hm); \ +} \ +\ +\ +static struct hashname##_entry * hashname##lookup(struct hashname##_ref *hm, codetype code) \ +{ \ + if (!hm) \ + return NULL; \ + /* fast modulo operation for power-of-2 size */ \ + unsigned int mask = hm->size - 1; \ + unsigned int i = hm->hash(code); \ + for (unsigned int j = 1; ; i += j++) { \ + if (!hm->bucket[i&mask].code || hm->compare(hm->bucket[i].code, code)) \ + return &(hm->bucket[i&mask]); \ + } \ + return NULL; \ +} \ +\ +\ +/* Find and return the element by code */ \ +struct hashname##_entry * hashname##_search(struct hashname##_ref *hm, codetype code) \ +{ \ + if (!hm) \ + return NULL; \ + struct hashname##_entry *r = hashname##lookup(hm, code); \ + if (r && hm->compare(r->code, code)) \ + return r; \ + return NULL; \ +} \ +\ +\ +/* FIXME: this simply overrides the found item */ \ +struct hashname##_entry * hashname##_insert(struct hashname##_ref *hm, struct hashname##_entry *entry) \ +{ \ + struct hashname##_entry *r = hashname##lookup(hm, entry->code); \ + if (r) { \ + if (!r->code) \ + hm->items++; \ + *r = *entry; \ + } \ + return r; \ +} \ +\ +\ +/* returns the number of removed items */ \ +int hashname##_remove(struct hashname##_ref *hm, codetype code) \ +{ \ + if (!hm) \ + return -1; \ + unsigned int mask = hm->size - 1; \ + unsigned int s = hm->hash(code)&mask, inc = 0; \ + struct hashname##_entry *r; \ + /* Flag for removal */ \ + while (hm->items > 0 && (r = hashname##lookup(hm, code)) && r->code) { \ + /* FIXME: this cast may not work */ \ + r->code = (codetype)(-1); \ + hm->items--; \ + } \ + /* Remove */ \ + for (unsigned int i = s; i < hm->items; i++) { \ + if (hm->bucket[i].code == (codetype)(-1)) { \ + hm->bucket[i] = (struct hashname##_entry){0}; \ + inc++; \ + } \ + } \ + return inc; \ +} \ + +#endif