diff --git a/src/commit.c b/src/commit.c index 44e1e94e2..3eebb927a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -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 */ if (commit->parents.contents == NULL) { - git_vector_init(&commit->parents, 4, NULL, NULL); + git_vector_init(&commit->parents, 4, NULL); } clear_parents(commit); diff --git a/src/index.c b/src/index.c index e83d11583..46bbafd3f 100644 --- a/src/index.c +++ b/src/index.c @@ -141,10 +141,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const index->repository = owner; - git_vector_init(&index->entries, 32, index_cmp, index_srch); - - /* the index is empty; the index is sorted */ - index->sorted = 1; + git_vector_init(&index->entries, 32, index_cmp); /* Check if index file is stored on disk already */ if (gitfo_exists(index->index_file_path) == 0) @@ -209,7 +206,6 @@ void git_index_clear(git_index *index) git_vector_clear(&index->entries); index->last_modified = 0; - index->sorted = 1; free_tree(index->tree); index->tree = NULL; @@ -259,8 +255,7 @@ int git_index_write(git_index *index) struct stat indexst; 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) return error; @@ -340,10 +335,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage) void sort_index(git_index *index) { - if (index->sorted == 0) { - git_vector_sort(&index->entries); - index->sorted = 1; - } + git_vector_sort(&index->entries); } 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) return GIT_ENOMEM; - index->sorted = 0; - /* if a previous entry exists, replace it */ } else { git_index_entry **entry_array = (git_index_entry **)index->entries.contents; @@ -413,7 +403,7 @@ int git_index_remove(git_index *index, int position) int git_index_find(git_index *index, const char *path) { 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( @@ -678,6 +668,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) #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; } diff --git a/src/index.h b/src/index.h index 43aadff0f..e1e752f7c 100644 --- a/src/index.h +++ b/src/index.h @@ -27,9 +27,7 @@ struct git_index { time_t last_modified; git_vector entries; - unsigned int sorted:1, - on_disk:1; - + unsigned int on_disk:1; git_index_tree *tree; }; diff --git a/src/odb.c b/src/odb.c index 4e54c749a..2013ac24c 100644 --- a/src/odb.c +++ b/src/odb.c @@ -162,7 +162,7 @@ int git_odb_new(git_odb **out) if (!db) 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); return GIT_ENOMEM; } diff --git a/src/refs.c b/src/refs.c index f8da56154..542401c2f 100644 --- a/src/refs.c +++ b/src/refs.c @@ -751,7 +751,7 @@ static int packed_write(git_repository *repo) assert(repo && repo->references.packfile); 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; /* Load all the packfile into a vector */ diff --git a/src/tree.c b/src/tree.c index 656798c63..5ea062286 100644 --- a/src/tree.c +++ b/src/tree.c @@ -83,10 +83,7 @@ git_tree *git_tree__new(void) memset(tree, 0x0, sizeof(struct git_tree)); - if (git_vector_init(&tree->entries, - DEFAULT_TREE_SIZE, - entry_sort_cmp, - entry_search_cmp) < GIT_SUCCESS) { + if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) { free(tree); return NULL; } @@ -173,7 +170,7 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) if (!tree->sorted) sort_entries(tree); - idx = git_vector_search(&tree->entries, filename); + idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename); if (idx == GIT_ENOTFOUND) return NULL; @@ -253,7 +250,7 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename) if (!tree->sorted) sort_entries(tree); - idx = git_vector_search(&tree->entries, filename); + idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename); if (idx == GIT_ENOTFOUND) return GIT_ENOTFOUND; diff --git a/src/vector.c b/src/vector.c index f298804e2..126aec1bb 100644 --- a/src/vector.c +++ b/src/vector.c @@ -50,7 +50,7 @@ void git_vector_free(git_vector *v) 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); @@ -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->_cmp = cmp; - v->_srch = srch; v->length = 0; + v->sorted = 1; v->contents = git__malloc(v->_alloc_size * sizeof(void *)); if (v->contents == NULL) @@ -82,6 +82,7 @@ int git_vector_insert(git_vector *v, void *element) } v->contents[v->length++] = element; + v->sorted = 0; return GIT_SUCCESS; } @@ -90,22 +91,56 @@ void git_vector_sort(git_vector *v) { assert(v); - if (v->_cmp != NULL) - qsort(v->contents, v->length, sizeof(void *), v->_cmp); + if (v->sorted || v->_cmp == NULL) + return; + + qsort(v->contents, v->length, sizeof(void *), v->_cmp); + v->sorted = 1; +} + +int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key) +{ + void **find; + + 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) { - void **find; - - if (v->_srch == NULL) + if (v->_cmp == NULL) return GIT_ENOTFOUND; - find = bsearch(key, v->contents, v->length, sizeof(void *), v->_srch); - if (find == NULL) + return git_vector_search2(v, v->_cmp, key); +} + +int git_vector_bsearch(git_vector *v, const void *key) +{ + if (v->_cmp == NULL) 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) @@ -128,6 +163,7 @@ void git_vector_clear(git_vector *v) { assert(v); v->length = 0; + v->sorted = 1; } diff --git a/src/vector.h b/src/vector.h index dfd604765..256452ee5 100644 --- a/src/vector.h +++ b/src/vector.h @@ -3,25 +3,26 @@ #include "git2/common.h" - typedef int (*git_vector_cmp)(const void *, const void *); -typedef int (*git_vector_srch)(const void *, const void *); typedef struct git_vector { unsigned int _alloc_size; git_vector_cmp _cmp; - git_vector_srch _srch; - void **contents; unsigned int length; + int sorted; } git_vector; - -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); void git_vector_free(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); GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position) diff --git a/tests/t00-core.c b/tests/t00-core.c index 3c1b6219a..1f6c06a95 100644 --- a/tests/t00-core.c +++ b/tests/t00-core.c @@ -64,7 +64,7 @@ END_TEST BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds") git_vector x; int i; - git_vector_init(&x, 1, NULL, NULL); + git_vector_init(&x, 1, NULL); for (i = 0; i < 10; ++i) { git_vector_insert(&x, (void*) 0xabc); } @@ -74,7 +74,7 @@ END_TEST BEGIN_TEST(vector1, "don't read past array bounds on remove()") git_vector x; // 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*) 0xdef); git_vector_insert(&x, (void*) 0x123); diff --git a/tests/t06-index.c b/tests/t06-index.c index 0c748cc8d..19b4da5c2 100644 --- a/tests/t06-index.c +++ b/tests/t06-index.c @@ -55,7 +55,7 @@ BEGIN_TEST(read0, "load an empty index") must_be_true(index->on_disk == 0); must_be_true(git_index_entrycount(index) == 0); - must_be_true(index->sorted); + must_be_true(index->entries.sorted); git_index_free(index); END_TEST @@ -72,7 +72,7 @@ BEGIN_TEST(read1, "load a standard index (default test index)") must_be_true(index->on_disk); 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; @@ -97,7 +97,7 @@ BEGIN_TEST(read2, "load a standard index (git.git index)") must_be_true(index->on_disk); 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); git_index_free(index); @@ -168,7 +168,7 @@ BEGIN_TEST(sort1, "sort the entires in an empty index") must_pass(git_index_open_bare(&index, "fake-index")); /* FIXME: this test is slightly dumb */ - must_be_true(index->sorted); + must_be_true(index->entries.sorted); git_index_free(index); END_TEST