Commit 86d7e1ca by Vicent Marti

Fix searching in git_vector

We now store only one sorting callback that does entry comparison. This
is used when sorting the entries using a quicksort, and when looking for
a specific entry with the new search methods.

The following search methods now exist:

	git_vector_search(vector, entry)
	git_vector_search2(vector, custom_search_callback, key)

	git_vector_bsearch(vector, entry)
	git_vector_bsearch2(vector, custom_search_callback, key)

The sorting state of the vector is now stored internally.

Signed-off-by: Vicent Marti <tanoku@gmail.com>
parent 5de079b8
...@@ -112,7 +112,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int ...@@ -112,7 +112,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
/* first parse; the vector hasn't been initialized yet */ /* first parse; the vector hasn't been initialized yet */
if (commit->parents.contents == NULL) { if (commit->parents.contents == NULL) {
git_vector_init(&commit->parents, 4, NULL, NULL); git_vector_init(&commit->parents, 4, NULL);
} }
clear_parents(commit); clear_parents(commit);
......
...@@ -141,10 +141,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const ...@@ -141,10 +141,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const
index->repository = owner; index->repository = owner;
git_vector_init(&index->entries, 32, index_cmp, index_srch); git_vector_init(&index->entries, 32, index_cmp);
/* the index is empty; the index is sorted */
index->sorted = 1;
/* Check if index file is stored on disk already */ /* Check if index file is stored on disk already */
if (gitfo_exists(index->index_file_path) == 0) if (gitfo_exists(index->index_file_path) == 0)
...@@ -209,7 +206,6 @@ void git_index_clear(git_index *index) ...@@ -209,7 +206,6 @@ void git_index_clear(git_index *index)
git_vector_clear(&index->entries); git_vector_clear(&index->entries);
index->last_modified = 0; index->last_modified = 0;
index->sorted = 1;
free_tree(index->tree); free_tree(index->tree);
index->tree = NULL; index->tree = NULL;
...@@ -259,8 +255,7 @@ int git_index_write(git_index *index) ...@@ -259,8 +255,7 @@ int git_index_write(git_index *index)
struct stat indexst; struct stat indexst;
int error; int error;
if (!index->sorted) sort_index(index);
sort_index(index);
if ((error = git_filebuf_open(&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < GIT_SUCCESS) if ((error = git_filebuf_open(&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < GIT_SUCCESS)
return error; return error;
...@@ -340,10 +335,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage) ...@@ -340,10 +335,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
void sort_index(git_index *index) void sort_index(git_index *index)
{ {
if (index->sorted == 0) { git_vector_sort(&index->entries);
git_vector_sort(&index->entries);
index->sorted = 1;
}
} }
int git_index_insert(git_index *index, const git_index_entry *source_entry) int git_index_insert(git_index *index, const git_index_entry *source_entry)
...@@ -388,8 +380,6 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry) ...@@ -388,8 +380,6 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry)
if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS) if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS)
return GIT_ENOMEM; return GIT_ENOMEM;
index->sorted = 0;
/* if a previous entry exists, replace it */ /* if a previous entry exists, replace it */
} else { } else {
git_index_entry **entry_array = (git_index_entry **)index->entries.contents; git_index_entry **entry_array = (git_index_entry **)index->entries.contents;
...@@ -413,7 +403,7 @@ int git_index_remove(git_index *index, int position) ...@@ -413,7 +403,7 @@ int git_index_remove(git_index *index, int position)
int git_index_find(git_index *index, const char *path) int git_index_find(git_index *index, const char *path)
{ {
sort_index(index); sort_index(index);
return git_vector_search(&index->entries, path); return git_vector_bsearch2(&index->entries, index_srch, path);
} }
static git_index_tree *read_tree_internal( static git_index_tree *read_tree_internal(
...@@ -678,6 +668,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) ...@@ -678,6 +668,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
#undef seek_forward #undef seek_forward
/* force sorting in the vector: the entries are
* assured to be sorted on the index */
index->entries.sorted = 1;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
......
...@@ -27,9 +27,7 @@ struct git_index { ...@@ -27,9 +27,7 @@ struct git_index {
time_t last_modified; time_t last_modified;
git_vector entries; git_vector entries;
unsigned int sorted:1, unsigned int on_disk:1;
on_disk:1;
git_index_tree *tree; git_index_tree *tree;
}; };
......
...@@ -162,7 +162,7 @@ int git_odb_new(git_odb **out) ...@@ -162,7 +162,7 @@ int git_odb_new(git_odb **out)
if (!db) if (!db)
return GIT_ENOMEM; return GIT_ENOMEM;
if (git_vector_init(&db->backends, 4, backend_sort_cmp, NULL) < 0) { if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
free(db); free(db);
return GIT_ENOMEM; return GIT_ENOMEM;
} }
......
...@@ -751,7 +751,7 @@ static int packed_write(git_repository *repo) ...@@ -751,7 +751,7 @@ static int packed_write(git_repository *repo)
assert(repo && repo->references.packfile); assert(repo && repo->references.packfile);
total_refs = repo->references.packfile->key_count; total_refs = repo->references.packfile->key_count;
if ((error = git_vector_init(&packing_list, total_refs, packed_sort, NULL)) < GIT_SUCCESS) if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
return error; return error;
/* Load all the packfile into a vector */ /* Load all the packfile into a vector */
......
...@@ -83,10 +83,7 @@ git_tree *git_tree__new(void) ...@@ -83,10 +83,7 @@ git_tree *git_tree__new(void)
memset(tree, 0x0, sizeof(struct git_tree)); memset(tree, 0x0, sizeof(struct git_tree));
if (git_vector_init(&tree->entries, if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) {
DEFAULT_TREE_SIZE,
entry_sort_cmp,
entry_search_cmp) < GIT_SUCCESS) {
free(tree); free(tree);
return NULL; return NULL;
} }
...@@ -173,7 +170,7 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) ...@@ -173,7 +170,7 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
if (!tree->sorted) if (!tree->sorted)
sort_entries(tree); sort_entries(tree);
idx = git_vector_search(&tree->entries, filename); idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
if (idx == GIT_ENOTFOUND) if (idx == GIT_ENOTFOUND)
return NULL; return NULL;
...@@ -253,7 +250,7 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename) ...@@ -253,7 +250,7 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
if (!tree->sorted) if (!tree->sorted)
sort_entries(tree); sort_entries(tree);
idx = git_vector_search(&tree->entries, filename); idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
if (idx == GIT_ENOTFOUND) if (idx == GIT_ENOTFOUND)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
......
...@@ -50,7 +50,7 @@ void git_vector_free(git_vector *v) ...@@ -50,7 +50,7 @@ void git_vector_free(git_vector *v)
free(v->contents); free(v->contents);
} }
int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp, git_vector_srch srch) int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp)
{ {
assert(v); assert(v);
...@@ -61,9 +61,9 @@ int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp ...@@ -61,9 +61,9 @@ int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp
v->_alloc_size = initial_size; v->_alloc_size = initial_size;
v->_cmp = cmp; v->_cmp = cmp;
v->_srch = srch;
v->length = 0; v->length = 0;
v->sorted = 1;
v->contents = git__malloc(v->_alloc_size * sizeof(void *)); v->contents = git__malloc(v->_alloc_size * sizeof(void *));
if (v->contents == NULL) if (v->contents == NULL)
...@@ -82,6 +82,7 @@ int git_vector_insert(git_vector *v, void *element) ...@@ -82,6 +82,7 @@ int git_vector_insert(git_vector *v, void *element)
} }
v->contents[v->length++] = element; v->contents[v->length++] = element;
v->sorted = 0;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -90,22 +91,56 @@ void git_vector_sort(git_vector *v) ...@@ -90,22 +91,56 @@ void git_vector_sort(git_vector *v)
{ {
assert(v); assert(v);
if (v->_cmp != NULL) if (v->sorted || v->_cmp == NULL)
qsort(v->contents, v->length, sizeof(void *), v->_cmp); return;
qsort(v->contents, v->length, sizeof(void *), v->_cmp);
v->sorted = 1;
} }
int git_vector_search(git_vector *v, const void *key) int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key)
{ {
void **find; void **find;
if (v->_srch == NULL) assert(v && key && key_lookup);
git_vector_sort(v);
find = bsearch(key, v->contents, v->length, sizeof(void *), key_lookup);
if (find != NULL)
return (int)(find - v->contents);
return GIT_ENOTFOUND;
}
int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key)
{
unsigned int i;
assert(v && key && key_lookup);
for (i = 0; i < v->length; ++i) {
if (key_lookup(key, v->contents[i]) == 0)
return i;
}
return GIT_ENOTFOUND;
}
int git_vector_search(git_vector *v, const void *key)
{
if (v->_cmp == NULL)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
find = bsearch(key, v->contents, v->length, sizeof(void *), v->_srch); return git_vector_search2(v, v->_cmp, key);
if (find == NULL) }
int git_vector_bsearch(git_vector *v, const void *key)
{
if (v->_cmp == NULL)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
return (int)(find - v->contents); return git_vector_bsearch2(v, v->_cmp, key);
} }
int git_vector_remove(git_vector *v, unsigned int idx) int git_vector_remove(git_vector *v, unsigned int idx)
...@@ -128,6 +163,7 @@ void git_vector_clear(git_vector *v) ...@@ -128,6 +163,7 @@ void git_vector_clear(git_vector *v)
{ {
assert(v); assert(v);
v->length = 0; v->length = 0;
v->sorted = 1;
} }
...@@ -3,25 +3,26 @@ ...@@ -3,25 +3,26 @@
#include "git2/common.h" #include "git2/common.h"
typedef int (*git_vector_cmp)(const void *, const void *); typedef int (*git_vector_cmp)(const void *, const void *);
typedef int (*git_vector_srch)(const void *, const void *);
typedef struct git_vector { typedef struct git_vector {
unsigned int _alloc_size; unsigned int _alloc_size;
git_vector_cmp _cmp; git_vector_cmp _cmp;
git_vector_srch _srch;
void **contents; void **contents;
unsigned int length; unsigned int length;
int sorted;
} git_vector; } git_vector;
int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp);
int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp, git_vector_srch srch);
void git_vector_free(git_vector *v); void git_vector_free(git_vector *v);
void git_vector_clear(git_vector *v); void git_vector_clear(git_vector *v);
int git_vector_search(git_vector *v, const void *key); int git_vector_search(git_vector *v, const void *entry);
int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key);
int git_vector_bsearch(git_vector *v, const void *entry);
int git_vector_bsearch2(git_vector *v, git_vector_cmp cmp, const void *key);
void git_vector_sort(git_vector *v); void git_vector_sort(git_vector *v);
GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position) GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position)
......
...@@ -64,7 +64,7 @@ END_TEST ...@@ -64,7 +64,7 @@ END_TEST
BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds") BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds")
git_vector x; git_vector x;
int i; int i;
git_vector_init(&x, 1, NULL, NULL); git_vector_init(&x, 1, NULL);
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
git_vector_insert(&x, (void*) 0xabc); git_vector_insert(&x, (void*) 0xabc);
} }
...@@ -74,7 +74,7 @@ END_TEST ...@@ -74,7 +74,7 @@ END_TEST
BEGIN_TEST(vector1, "don't read past array bounds on remove()") BEGIN_TEST(vector1, "don't read past array bounds on remove()")
git_vector x; git_vector x;
// make initial capacity exact for our insertions. // make initial capacity exact for our insertions.
git_vector_init(&x, 3, NULL, NULL); git_vector_init(&x, 3, NULL);
git_vector_insert(&x, (void*) 0xabc); git_vector_insert(&x, (void*) 0xabc);
git_vector_insert(&x, (void*) 0xdef); git_vector_insert(&x, (void*) 0xdef);
git_vector_insert(&x, (void*) 0x123); git_vector_insert(&x, (void*) 0x123);
......
...@@ -55,7 +55,7 @@ BEGIN_TEST(read0, "load an empty index") ...@@ -55,7 +55,7 @@ BEGIN_TEST(read0, "load an empty index")
must_be_true(index->on_disk == 0); must_be_true(index->on_disk == 0);
must_be_true(git_index_entrycount(index) == 0); must_be_true(git_index_entrycount(index) == 0);
must_be_true(index->sorted); must_be_true(index->entries.sorted);
git_index_free(index); git_index_free(index);
END_TEST END_TEST
...@@ -72,7 +72,7 @@ BEGIN_TEST(read1, "load a standard index (default test index)") ...@@ -72,7 +72,7 @@ BEGIN_TEST(read1, "load a standard index (default test index)")
must_be_true(index->on_disk); must_be_true(index->on_disk);
must_be_true(git_index_entrycount(index) == TEST_INDEX_ENTRY_COUNT); must_be_true(git_index_entrycount(index) == TEST_INDEX_ENTRY_COUNT);
must_be_true(index->sorted); must_be_true(index->entries.sorted);
entries = (git_index_entry **)index->entries.contents; entries = (git_index_entry **)index->entries.contents;
...@@ -97,7 +97,7 @@ BEGIN_TEST(read2, "load a standard index (git.git index)") ...@@ -97,7 +97,7 @@ BEGIN_TEST(read2, "load a standard index (git.git index)")
must_be_true(index->on_disk); must_be_true(index->on_disk);
must_be_true(git_index_entrycount(index) == TEST_INDEX2_ENTRY_COUNT); must_be_true(git_index_entrycount(index) == TEST_INDEX2_ENTRY_COUNT);
must_be_true(index->sorted); must_be_true(index->entries.sorted);
must_be_true(index->tree != NULL); must_be_true(index->tree != NULL);
git_index_free(index); git_index_free(index);
...@@ -168,7 +168,7 @@ BEGIN_TEST(sort1, "sort the entires in an empty index") ...@@ -168,7 +168,7 @@ BEGIN_TEST(sort1, "sort the entires in an empty index")
must_pass(git_index_open_bare(&index, "fake-index")); must_pass(git_index_open_bare(&index, "fake-index"));
/* FIXME: this test is slightly dumb */ /* FIXME: this test is slightly dumb */
must_be_true(index->sorted); must_be_true(index->entries.sorted);
git_index_free(index); git_index_free(index);
END_TEST END_TEST
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment