diff options
Diffstat (limited to 'src/hashtable.c')
| -rw-r--r-- | src/hashtable.c | 328 |
1 files changed, 0 insertions, 328 deletions
diff --git a/src/hashtable.c b/src/hashtable.c deleted file mode 100644 index e2f131cf1..000000000 --- a/src/hashtable.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2009-2012 the libgit2 contributors - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "common.h" -#include "repository.h" -#include "commit.h" - -#define MAX_LOOPS 5 -static const double max_load_factor = 0.65; - -static int resize_to(git_hashtable *self, size_t new_size); -static int set_size(git_hashtable *self, size_t new_size); -static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id); -static void node_swap_with(git_hashtable_node *self, git_hashtable_node *other); -static int node_insert(git_hashtable *self, git_hashtable_node *new_node); -static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size); -static void reinsert_stash(git_hashtable *self); - -static int resize_to(git_hashtable *self, size_t new_size) -{ - git_hashtable_node *old_nodes = self->nodes; - size_t old_size = self->size; - git_hashtable_node old_stash[GIT_HASHTABLE_STASH_SIZE]; - size_t old_stash_count = self->stash_count; - - self->is_resizing = 1; - - if (old_stash_count > 0) - memcpy(old_stash, self->stash, - old_stash_count * sizeof(git_hashtable_node)); - - do { - self->size = new_size; - self->size_mask = new_size - 1; - self->key_count = 0; - self->stash_count = 0; - self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size); - GITERR_CHECK_ALLOC(self->nodes); - - if (insert_nodes(self, old_nodes, old_size) == 0 && - insert_nodes(self, old_stash, old_stash_count) == 0) - self->is_resizing = 0; - else { - new_size *= 2; - git__free(self->nodes); - } - } while (self->is_resizing); - - git__free(old_nodes); - return 0; -} - -static int set_size(git_hashtable *self, size_t new_size) -{ - self->nodes = - git__realloc(self->nodes, new_size * sizeof(git_hashtable_node)); - GITERR_CHECK_ALLOC(self->nodes); - - if (new_size > self->size) - memset(&self->nodes[self->size], 0x0, - (new_size - self->size) * sizeof(git_hashtable_node)); - - self->size = new_size; - self->size_mask = new_size - 1; - return 0; -} - -GIT_INLINE(git_hashtable_node *)node_with_hash( - git_hashtable *self, const void *key, int hash_id) -{ - size_t pos = self->hash(key, hash_id) & self->size_mask; - return git_hashtable_node_at(self->nodes, pos); -} - -GIT_INLINE(void) node_swap_with( - git_hashtable_node *self, git_hashtable_node *other) -{ - git_hashtable_node tmp = *self; - *self = *other; - *other = tmp; -} - -static int node_insert(git_hashtable *self, git_hashtable_node *new_node) -{ - int iteration, hash_id; - git_hashtable_node *node; - - for (iteration = 0; iteration < MAX_LOOPS; iteration++) { - for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { - node = node_with_hash(self, new_node->key, hash_id); - node_swap_with(new_node, node); - if (new_node->key == 0x0) { - self->key_count++; - return 0; - } - } - } - - /* Insert into stash if there is space */ - if (self->stash_count < GIT_HASHTABLE_STASH_SIZE) { - node_swap_with(new_node, &self->stash[self->stash_count++]); - self->key_count++; - return 0; - } - - /* Failed to insert node. Hashtable is currently resizing */ - assert(!self->is_resizing); - - if (resize_to(self, self->size * 2) < 0) - return -1; - - return git_hashtable_insert(self, new_node->key, new_node->value); -} - -static int insert_nodes( - git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size) -{ - size_t i; - - for (i = 0; i < old_size; ++i) { - git_hashtable_node *node = git_hashtable_node_at(old_nodes, i); - if (node->key && node_insert(self, node) < 0) - return -1; - } - - return 0; -} - -static void reinsert_stash(git_hashtable *self) -{ - int stash_count; - struct git_hashtable_node stash[GIT_HASHTABLE_STASH_SIZE]; - - if (self->stash_count <= 0) - return; - - memcpy(stash, self->stash, self->stash_count * sizeof(git_hashtable_node)); - stash_count = self->stash_count; - self->stash_count = 0; - - /* the node_insert() calls *cannot* fail because the stash is empty */ - insert_nodes(self, stash, stash_count); -} - -git_hashtable *git_hashtable_alloc( - size_t min_size, - git_hash_ptr hash, - git_hash_keyeq_ptr key_eq) -{ - git_hashtable *table; - - assert(hash && key_eq); - - if ((table = git__malloc(sizeof(*table))) == NULL) - return NULL; - - memset(table, 0x0, sizeof(git_hashtable)); - - table->hash = hash; - table->key_equal = key_eq; - - min_size = git__size_t_powerof2(min_size < 8 ? 8 : min_size); - set_size(table, min_size); - - return table; -} - -void git_hashtable_clear(git_hashtable *self) -{ - assert(self); - - memset(self->nodes, 0x0, sizeof(git_hashtable_node) * self->size); - - self->stash_count = 0; - self->key_count = 0; -} - -void git_hashtable_free(git_hashtable *self) -{ - assert(self); - - git__free(self->nodes); - git__free(self); -} - - -int git_hashtable_insert2( - git_hashtable *self, const void *key, void *value, void **old_value) -{ - int hash_id; - git_hashtable_node *node; - - assert(self && self->nodes); - - *old_value = NULL; - - for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { - node = node_with_hash(self, key, hash_id); - - if (!node->key) { - node->key = key; - node->value = value; - self->key_count++; - return 0; - } - - if (key == node->key || self->key_equal(key, node->key) == 0) { - *old_value = node->value; - node->key = key; - node->value = value; - return 0; - } - } - - /* no space in table; must do cuckoo dance */ - { - git_hashtable_node x; - x.key = key; - x.value = value; - return node_insert(self, &x); - } -} - -static git_hashtable_node *find_node(git_hashtable *self, const void *key) -{ - int hash_id, count = 0; - git_hashtable_node *node; - - for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { - node = node_with_hash(self, key, hash_id); - if (node->key) { - ++count; - if (self->key_equal(key, node->key) == 0) - return node; - } - } - - /* check stash if not found but all slots were filled */ - if (count == GIT_HASHTABLE_HASHES) { - for (count = 0; count < self->stash_count; ++count) - if (self->key_equal(key, self->stash[count].key) == 0) - return &self->stash[count]; - } - - return NULL; -} - -static void reset_stash(git_hashtable *self, git_hashtable_node *node) -{ - /* if node was in stash, then compact stash */ - ssize_t offset = node - self->stash; - - if (offset >= 0 && offset < self->stash_count) { - if (offset < self->stash_count - 1) - memmove(node, node + 1, (self->stash_count - offset) * - sizeof(git_hashtable_node)); - self->stash_count--; - } - - reinsert_stash(self); -} - -void *git_hashtable_lookup(git_hashtable *self, const void *key) -{ - git_hashtable_node *node; - assert(self && key); - node = find_node(self, key); - return node ? node->value : NULL; -} - -int git_hashtable_remove2( - git_hashtable *self, const void *key, void **old_value) -{ - git_hashtable_node *node; - - assert(self && self->nodes); - - node = find_node(self, key); - if (node) { - *old_value = node->value; - - node->key = NULL; - node->value = NULL; - self->key_count--; - - reset_stash(self, node); - return 0; - } - - return GIT_ENOTFOUND; -} - -int git_hashtable_merge(git_hashtable *self, git_hashtable *other) -{ - size_t new_size = git__size_t_powerof2(self->size + other->size); - - if (resize_to(self, new_size) < 0) - return -1; - - if (insert_nodes(self, other->nodes, other->key_count) < 0) - return -1; - - return insert_nodes(self, other->stash, other->stash_count); -} - - -/** - * Standard string - */ -uint32_t git_hash__strhash_cb(const void *key, int hash_id) -{ - static uint32_t hash_seeds[GIT_HASHTABLE_HASHES] = { - 2147483647, - 0x5d20bb23, - 0x7daaab3c - }; - - size_t key_len = strlen((const char *)key); - - /* won't take hash of strings longer than 2^31 right now */ - assert(key_len == (size_t)((int)key_len)); - - return git__hash(key, (int)key_len, hash_seeds[hash_id]); -} |
