mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-13 08:27:06 +00:00
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>
This commit is contained in:
parent
5de079b86d
commit
86d7e1ca6f
@ -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);
|
||||||
|
21
src/index.c
21
src/index.c
@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
#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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
|
||||||
|
56
src/vector.c
56
src/vector.c
@ -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
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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_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)
|
int git_vector_search(git_vector *v, const void *key)
|
||||||
{
|
{
|
||||||
void **find;
|
if (v->_cmp == NULL)
|
||||||
|
|
||||||
if (v->_srch == 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)
|
|||||||
{
|
{
|
||||||
assert(v);
|
assert(v);
|
||||||
v->length = 0;
|
v->length = 0;
|
||||||
|
v->sorted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
15
src/vector.h
15
src/vector.h
@ -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
|
|||||||
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
|
|||||||
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")
|
|||||||
|
|
||||||
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)")
|
|||||||
|
|
||||||
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)")
|
|||||||
|
|
||||||
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")
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user