summaryrefslogtreecommitdiffstats
path: root/src/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hash.c')
-rw-r--r--src/hash.c226
1 files changed, 0 insertions, 226 deletions
diff --git a/src/hash.c b/src/hash.c
deleted file mode 100644
index f654e91..0000000
--- a/src/hash.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- Copyright 2011 David Robillard <http://drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "zix/hash.h"
-
-/**
- Primes, each slightly less than twice its predecessor, and as far away
- from powers of two as possible.
-*/
-static const unsigned sizes[] = {
- 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317,
- 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843,
- 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 0
-};
-
-typedef struct _Entry {
- const void* key; ///< Hash key
- void* data; ///< Value
- struct _Entry* next; ///< Next entry in bucket
- unsigned hash; ///< Non-modulo hash value (for cheap rehash)
-} Entry;
-
-struct ZixHashImpl {
- ZixHashFunc hash_func;
- ZixEqualFunc key_equal_func;
- Entry** buckets;
- const unsigned* n_buckets;
- unsigned count;
-};
-
-ZixHash*
-zix_hash_new(ZixHashFunc hash_func,
- ZixEqualFunc key_equal_func)
-
-{
- ZixHash* hash = (ZixHash*)malloc(sizeof(ZixHash));
- hash->hash_func = hash_func;
- hash->key_equal_func = key_equal_func;
- hash->count = 0;
- hash->n_buckets = &sizes[0];
- hash->buckets = (Entry**)malloc(*hash->n_buckets * sizeof(Entry*));
- memset(hash->buckets, 0, *hash->n_buckets * sizeof(Entry*));
-
- return hash;
-}
-
-void
-zix_hash_free(ZixHash* hash)
-{
- for (unsigned b = 0; b < *hash->n_buckets; ++b) {
- Entry* bucket = hash->buckets[b];
- for (Entry* e = bucket; e;) {
- Entry* next = e->next;
- free(e);
- e = next;
- }
- }
-
- free(hash->buckets);
- free(hash);
-}
-
-unsigned
-zix_string_hash(const void* key)
-{
- // Trusty old DJB hash
- const char* str = (const char*)key;
- unsigned h = 5381;
- for (const char* s = str; *s != '\0'; ++s) {
- h = (h << 5) + h + *s; // h = h * 33 + c
- }
- return h;
-}
-
-bool
-zix_string_equal(const void* a, const void* b)
-{
- return !strcmp((const char*)a, (const char*)b);
-}
-
-static void
-insert_entry(Entry** bucket,
- Entry* entry)
-{
- entry->next = *bucket;
- *bucket = entry;
-}
-
-static ZixStatus
-rehash(ZixHash* hash, unsigned new_n_buckets)
-{
- Entry** new_buckets = (Entry**)malloc(new_n_buckets * sizeof(Entry*));
- if (!new_buckets) {
- return ZIX_STATUS_NO_MEM;
- }
-
- memset(new_buckets, 0, new_n_buckets * sizeof(Entry*));
-
- for (unsigned b = 0; b < *hash->n_buckets; ++b) {
- for (Entry* e = hash->buckets[b]; e;) {
- Entry* const next = e->next;
- const unsigned h = e->hash % new_n_buckets;
- insert_entry(&new_buckets[h], e);
- e = next;
- }
- }
-
- free(hash->buckets);
- hash->buckets = new_buckets;
-
- return ZIX_STATUS_SUCCESS;
-}
-
-static Entry*
-find_entry(const ZixHash* hash,
- const void* key,
- unsigned h)
-{
- for (Entry* e = hash->buckets[h]; e; e = e->next) {
- if (hash->key_equal_func(e->key, key)) {
- return e;
- }
- }
-
- return NULL;
-}
-
-void*
-zix_hash_find(const ZixHash* hash, const void* key)
-{
- const unsigned h = hash->hash_func(key) % *hash->n_buckets;
- Entry* const entry = find_entry(hash, key, h);
- return entry ? entry->data : 0;
-}
-
-ZixStatus
-zix_hash_insert(ZixHash* hash, const void* key, void* data)
-{
- unsigned h_nomod = hash->hash_func(key);
- unsigned h = h_nomod % *hash->n_buckets;
-
- Entry* elem = find_entry(hash, key, h);
- if (elem) {
- assert(elem->hash == h_nomod);
- return ZIX_STATUS_EXISTS;
- }
-
- elem = (Entry*)malloc(sizeof(Entry));
- if (!elem) {
- return ZIX_STATUS_NO_MEM;
- }
- elem->key = key;
- elem->data = data;
- elem->next = NULL;
- elem->hash = h_nomod;
- const unsigned next_n_buckets = *(hash->n_buckets + 1);
- if (next_n_buckets != 0 && (hash->count + 1) >= next_n_buckets) {
- if (!rehash(hash, next_n_buckets)) {
- h = h_nomod % *(++hash->n_buckets);
- }
- }
-
- insert_entry(&hash->buckets[h], elem);
- ++hash->count;
- return ZIX_STATUS_SUCCESS;
-}
-
-ZixStatus
-zix_hash_remove(ZixHash* hash, const void* key)
-{
- unsigned h = hash->hash_func(key) % *hash->n_buckets;
-
- Entry** next_ptr = &hash->buckets[h];
- for (Entry* e = hash->buckets[h]; e; e = e->next) {
- if (hash->key_equal_func(e->key, key)) {
- *next_ptr = e->next;
- free(e);
- return ZIX_STATUS_SUCCESS;
- }
- next_ptr = &e->next;
- }
-
- if (hash->n_buckets != sizes) {
- const unsigned prev_n_buckets = *(hash->n_buckets - 1);
- if (hash->count - 1 <= prev_n_buckets) {
- if (!rehash(hash, prev_n_buckets)) {
- --hash->n_buckets;
- }
- }
- }
-
- --hash->count;
- return ZIX_STATUS_NOT_FOUND;
-}
-
-ZIX_API
-void
-zix_hash_foreach(const ZixHash* hash,
- void (*f)(const void* key, void* value, void* user_data),
- void* user_data)
-{
- for (unsigned b = 0; b < *hash->n_buckets; ++b) {
- Entry* bucket = hash->buckets[b];
- for (Entry* e = bucket; e; e = e->next) {
- f(e->key, e->data, user_data);
- }
- }
-}
-