diff options
author | Vicent Marti <tanoku@gmail.com> | 2010-05-22 23:21:10 +0200 |
---|---|---|
committer | Andreas Ericsson <ae@op5.se> | 2010-06-02 10:32:06 +0200 |
commit | c5696427b6d53a3f79baad35ea33c556884a410a (patch) | |
tree | cb3ab00e68da089aecd496ba4e39b1c706ed7c68 /src/revobject.c | |
parent | 36b7cdb6a1a2e685c7141406808366d4c4b9f98e (diff) | |
download | libgit2-c5696427b6d53a3f79baad35ea33c556884a410a.tar.gz |
Add 'git_revpool_object' and 'git_revpool_table' structures.
All the objects which will will be eventually transversable from
a revision pool (commits, trees, etc) now inherit from the
'git_revpool_object' structure which identifies them with their
own OID.
Furthermore, the 'git_revpool_table' and related functions have
been added, which allow for constant time lookup (hash table)
of the loaded revpool objects based on their OID.
Signed-off-by: Vicent Marti <tanoku@gmail.com>
Signed-off-by: Andreas Ericsson <ae@op5.se>
Diffstat (limited to 'src/revobject.c')
-rw-r--r-- | src/revobject.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/revobject.c b/src/revobject.c new file mode 100644 index 000000000..7c2513775 --- /dev/null +++ b/src/revobject.c @@ -0,0 +1,167 @@ +/* + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * In addition to the permissions in the GNU General Public License, + * the authors give you unlimited permission to link the compiled + * version of this file into combinations with other programs, + * and to distribute those combinations without any restriction + * coming from the use of this file. (The General Public License + * restrictions do apply in other respects; for example, they cover + * modification of the file, and distribution when not linked into + * a combined executable.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "common.h" +#include "revobject.h" + +const float max_load_factor = 0.65; + +unsigned int git_revpool_table__hash(const git_oid *id) +{ + const unsigned int m = 0x5bd1e995; + const int r = 24; + + unsigned int h = 0xA8A3D5 ^ (unsigned int)id; + int i; + + for (i = 0; i < GIT_OID_RAWSZ / 4; ++i) + { + unsigned int k = ((unsigned int *)id->id)[i]; + + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +git_revpool_table *git_revpool_table_create(unsigned int min_size) +{ + git_revpool_table *table; + + table = git__malloc(sizeof(table)); + + if (table == NULL) + return NULL; + + // round up size to closest power of 2 + min_size--; + min_size |= min_size >> 1; + min_size |= min_size >> 2; + min_size |= min_size >> 4; + min_size |= min_size >> 8; + min_size |= min_size >> 16; + + table->size_mask = min_size; + table->count = 0; + table->max_count = (min_size + 1) * max_load_factor; + + table->nodes = git__malloc((min_size + 1) * sizeof(git_revpool_node *)); + + if (table->nodes == NULL) + { + free(table); + return NULL; + } + + memset(table->nodes, 0x0, (min_size + 1) * sizeof(git_revpool_node *)); + + return table; +} + +int git_revpool_table_insert(git_revpool_table *table, git_revpool_object *object) +{ + git_revpool_node *node; + unsigned int index, hash; + + if (table->count + 1 > table->max_count) + git_revpool_table_resize(table); + + node = git__malloc(sizeof(git_revpool_node)); + if (node == NULL) + return -1; + + hash = git_revpool_table__hash(&object->id); + index = (hash & table->size_mask); + + node->object = object; + node->hash = hash; + node->next = table->nodes[index]; + + table->nodes[index] = node; + table->count++; + + return 0; +} + +git_revpool_object *git_revpool_table_lookup(git_revpool_table *table, const git_oid *id) +{ + git_revpool_node *node; + unsigned int index, hash; + + hash = git_revpool_table__hash(id); + index = (hash & table->size_mask); + node = table->nodes[index]; + + while (node != NULL) + { + if (node->hash == hash && git_oid_cmp(id, &node->object->id) == 0) + return node->object; + + node = node->next; + } + + return NULL; +} + +void git_revpool_table_resize(git_revpool_table *table) +{ + git_revpool_node **new_nodes; + unsigned int new_size, i; + + new_size = (table->size_mask + 1) * 2; + + new_nodes = git__malloc(new_size * sizeof(git_revpool_node *)); + if (new_nodes == NULL) + return; + + memset(new_nodes, 0x0, new_size * sizeof(git_revpool_node *)); + + for (i = 0; i <= table->size_mask; ++i) + { + git_revpool_node *n; + unsigned int index; + + while ((n = table->nodes[i]) != NULL) + { + table->nodes[i] = n->next; + index = n->hash & (new_size - 1); + n->next = new_nodes[index]; + new_nodes[index] = n; + } + } + + free(table->nodes); + table->nodes = new_nodes; + table->size_mask = (new_size - 1); + table->max_count = new_size * max_load_factor; +} |