mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 01:43:48 +00:00
Merge pull request #3704 from ethomson/tree-reuse
tree: drop the now-unnecessary entries vector
This commit is contained in:
commit
661db4f482
40
src/array.h
40
src/array.h
@ -82,4 +82,44 @@ on_oom:
|
||||
|
||||
#define git_array_valid_index(a, i) ((i) < (a).size)
|
||||
|
||||
#define git_array_foreach(a, i, element) \
|
||||
for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++)
|
||||
|
||||
|
||||
GIT_INLINE(int) git_array__search(
|
||||
size_t *out,
|
||||
void *array_ptr,
|
||||
size_t item_size,
|
||||
size_t array_len,
|
||||
int (*compare)(const void *, const void *),
|
||||
const void *key)
|
||||
{
|
||||
size_t lim;
|
||||
unsigned char *part, *array = array_ptr, *base = array_ptr;
|
||||
int cmp;
|
||||
|
||||
for (lim = array_len; lim != 0; lim >>= 1) {
|
||||
part = base + (lim >> 1) * item_size;
|
||||
cmp = (*compare)(key, part);
|
||||
|
||||
if (cmp == 0) {
|
||||
base = part;
|
||||
break;
|
||||
}
|
||||
if (cmp > 0) { /* key > p; take right partition */
|
||||
base = part + 1 * item_size;
|
||||
lim--;
|
||||
} /* else take left partition */
|
||||
}
|
||||
|
||||
if (out)
|
||||
*out = (base - array) / item_size;
|
||||
|
||||
return (cmp == 0) ? 0 : GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
#define git_array_search(out, a, cmp, key) \
|
||||
git_array__search(out, (a).ptr, sizeof(*(a).ptr), (a).size, \
|
||||
(cmp), (key))
|
||||
|
||||
#endif
|
||||
|
73
src/tree.c
73
src/tree.c
@ -163,7 +163,10 @@ static int homing_search_cmp(const void *key, const void *array_member)
|
||||
* around the area for our target file.
|
||||
*/
|
||||
static int tree_key_search(
|
||||
size_t *at_pos, git_vector *entries, const char *filename, size_t filename_len)
|
||||
size_t *at_pos,
|
||||
const git_tree *tree,
|
||||
const char *filename,
|
||||
size_t filename_len)
|
||||
{
|
||||
struct tree_key_search ksearch;
|
||||
const git_tree_entry *entry;
|
||||
@ -176,13 +179,15 @@ static int tree_key_search(
|
||||
|
||||
/* Initial homing search; find an entry on the tree with
|
||||
* the same prefix as the filename we're looking for */
|
||||
if (git_vector_bsearch2(&homing, entries, &homing_search_cmp, &ksearch) < 0)
|
||||
|
||||
if (git_array_search(&homing,
|
||||
tree->entries, &homing_search_cmp, &ksearch) < 0)
|
||||
return GIT_ENOTFOUND; /* just a signal error; not passed back to user */
|
||||
|
||||
/* We found a common prefix. Look forward as long as
|
||||
* there are entries that share the common prefix */
|
||||
for (i = homing; i < entries->length; ++i) {
|
||||
entry = entries->contents[i];
|
||||
for (i = homing; i < tree->entries.size; ++i) {
|
||||
entry = git_array_get(tree->entries, i);
|
||||
|
||||
if (homing_search_cmp(&ksearch, entry) < 0)
|
||||
break;
|
||||
@ -202,7 +207,7 @@ static int tree_key_search(
|
||||
i = homing - 1;
|
||||
|
||||
do {
|
||||
entry = entries->contents[i];
|
||||
entry = git_array_get(tree->entries, i);
|
||||
|
||||
if (homing_search_cmp(&ksearch, entry) > 0)
|
||||
break;
|
||||
@ -250,8 +255,7 @@ void git_tree__free(void *_tree)
|
||||
git_tree *tree = _tree;
|
||||
|
||||
git_odb_object_free(tree->odb_obj);
|
||||
git_vector_free(&tree->entries);
|
||||
git_array_clear(tree->entries_arr);
|
||||
git_array_clear(tree->entries);
|
||||
git__free(tree);
|
||||
}
|
||||
|
||||
@ -303,13 +307,10 @@ static const git_tree_entry *entry_fromname(
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
/* be safe when we cast away constness - i.e. don't trigger a sort */
|
||||
assert(git_vector_is_sorted(&tree->entries));
|
||||
|
||||
if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0)
|
||||
if (tree_key_search(&idx, tree, name, name_len) < 0)
|
||||
return NULL;
|
||||
|
||||
return git_vector_get(&tree->entries, idx);
|
||||
return git_array_get(tree->entries, idx);
|
||||
}
|
||||
|
||||
const git_tree_entry *git_tree_entry_byname(
|
||||
@ -324,7 +325,7 @@ const git_tree_entry *git_tree_entry_byindex(
|
||||
const git_tree *tree, size_t idx)
|
||||
{
|
||||
assert(tree);
|
||||
return git_vector_get(&tree->entries, idx);
|
||||
return git_array_get(tree->entries, idx);
|
||||
}
|
||||
|
||||
const git_tree_entry *git_tree_entry_byid(
|
||||
@ -335,7 +336,7 @@ const git_tree_entry *git_tree_entry_byid(
|
||||
|
||||
assert(tree);
|
||||
|
||||
git_vector_foreach(&tree->entries, i, e) {
|
||||
git_array_foreach(tree->entries, i, e) {
|
||||
if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0)
|
||||
return e;
|
||||
}
|
||||
@ -345,7 +346,6 @@ const git_tree_entry *git_tree_entry_byid(
|
||||
|
||||
int git_tree__prefix_position(const git_tree *tree, const char *path)
|
||||
{
|
||||
const git_vector *entries = &tree->entries;
|
||||
struct tree_key_search ksearch;
|
||||
size_t at_pos, path_len;
|
||||
|
||||
@ -358,21 +358,20 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
|
||||
ksearch.filename = path;
|
||||
ksearch.filename_len = (uint16_t)path_len;
|
||||
|
||||
/* be safe when we cast away constness - i.e. don't trigger a sort */
|
||||
assert(git_vector_is_sorted(&tree->entries));
|
||||
|
||||
/* Find tree entry with appropriate prefix */
|
||||
git_vector_bsearch2(
|
||||
&at_pos, (git_vector *)entries, &homing_search_cmp, &ksearch);
|
||||
git_array_search(
|
||||
&at_pos, tree->entries, &homing_search_cmp, &ksearch);
|
||||
|
||||
for (; at_pos < entries->length; ++at_pos) {
|
||||
const git_tree_entry *entry = entries->contents[at_pos];
|
||||
for (; at_pos < tree->entries.size; ++at_pos) {
|
||||
const git_tree_entry *entry = git_array_get(tree->entries, at_pos);
|
||||
if (homing_search_cmp(&ksearch, entry) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
for (; at_pos > 0; --at_pos) {
|
||||
const git_tree_entry *entry = entries->contents[at_pos - 1];
|
||||
const git_tree_entry *entry =
|
||||
git_array_get(tree->entries, at_pos - 1);
|
||||
|
||||
if (homing_search_cmp(&ksearch, entry) > 0)
|
||||
break;
|
||||
}
|
||||
@ -383,7 +382,7 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
|
||||
size_t git_tree_entrycount(const git_tree *tree)
|
||||
{
|
||||
assert(tree);
|
||||
return tree->entries.length;
|
||||
return tree->entries.size;
|
||||
}
|
||||
|
||||
unsigned int git_treebuilder_entrycount(git_treebuilder *bld)
|
||||
@ -423,7 +422,6 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff
|
||||
|
||||
int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
||||
{
|
||||
size_t i;
|
||||
git_tree *tree = _tree;
|
||||
const char *buffer;
|
||||
const char *buffer_end;
|
||||
@ -434,8 +432,8 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
||||
buffer = git_odb_object_data(tree->odb_obj);
|
||||
buffer_end = buffer + git_odb_object_size(tree->odb_obj);
|
||||
|
||||
git_array_init_to_size(tree->entries_arr, DEFAULT_TREE_SIZE);
|
||||
GITERR_CHECK_ARRAY(tree->entries_arr);
|
||||
git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE);
|
||||
GITERR_CHECK_ARRAY(tree->entries);
|
||||
|
||||
while (buffer < buffer_end) {
|
||||
git_tree_entry *entry;
|
||||
@ -450,9 +448,9 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
||||
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
||||
|
||||
filename_len = nul - buffer;
|
||||
/** Allocate the entry and store it in the entries vector */
|
||||
/* Allocate the entry */
|
||||
{
|
||||
entry = git_array_alloc(tree->entries_arr);
|
||||
entry = git_array_alloc(tree->entries);
|
||||
GITERR_CHECK_ALLOC(entry);
|
||||
|
||||
entry->attr = attr;
|
||||
@ -465,18 +463,6 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
||||
buffer += GIT_OID_RAWSZ;
|
||||
}
|
||||
|
||||
/* Add the entries to the vector here, as we may reallocate during the loop */
|
||||
if (git_vector_init(&tree->entries, tree->entries_arr.size, entry_sort_cmp) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < tree->entries_arr.size; i++) {
|
||||
if (git_vector_insert(&tree->entries, git_array_get(tree->entries_arr, i)) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The tree is sorted by definition. Bad inputs give bad outputs */
|
||||
tree->entries.flags |= GIT_VECTOR_SORTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -700,7 +686,7 @@ int git_treebuilder_new(
|
||||
if (source != NULL) {
|
||||
git_tree_entry *entry_src;
|
||||
|
||||
git_vector_foreach(&source->entries, i, entry_src) {
|
||||
git_array_foreach(source->entries, i, entry_src) {
|
||||
if (append_entry(
|
||||
bld, entry_src->filename,
|
||||
entry_src->oid,
|
||||
@ -845,7 +831,6 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
|
||||
error = -1;
|
||||
}
|
||||
|
||||
git_vector_free(&entries);
|
||||
|
||||
if (!error &&
|
||||
!(error = git_repository_odb__weakptr(&odb, bld->repo)))
|
||||
@ -975,7 +960,7 @@ static int tree_walk(
|
||||
size_t i;
|
||||
const git_tree_entry *entry;
|
||||
|
||||
git_vector_foreach(&tree->entries, i, entry) {
|
||||
git_array_foreach(tree->entries, i, entry) {
|
||||
if (preorder) {
|
||||
error = callback(path->ptr, entry, payload);
|
||||
if (error < 0) { /* negative value stops iteration */
|
||||
|
@ -24,8 +24,7 @@ struct git_tree_entry {
|
||||
struct git_tree {
|
||||
git_object object;
|
||||
git_odb_object *odb_obj;
|
||||
git_array_t(git_tree_entry) entries_arr;
|
||||
git_vector entries;
|
||||
git_array_t(git_tree_entry) entries;
|
||||
};
|
||||
|
||||
struct git_treebuilder {
|
||||
|
55
tests/core/array.c
Normal file
55
tests/core/array.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "array.h"
|
||||
|
||||
static int int_lookup(const void *k, const void *a)
|
||||
{
|
||||
const int *one = (const int *)k;
|
||||
int *two = (int *)a;
|
||||
|
||||
return *one - *two;
|
||||
}
|
||||
|
||||
#define expect_pos(k, n, ret) \
|
||||
key = (k); \
|
||||
cl_assert_equal_i((ret), \
|
||||
git_array_search(&p, integers, int_lookup, &key)); \
|
||||
cl_assert_equal_i((n), p);
|
||||
|
||||
void test_core_array__bsearch2(void)
|
||||
{
|
||||
git_array_t(int) integers = GIT_ARRAY_INIT;
|
||||
int *i, key;
|
||||
size_t p;
|
||||
|
||||
i = git_array_alloc(integers); *i = 2;
|
||||
i = git_array_alloc(integers); *i = 3;
|
||||
i = git_array_alloc(integers); *i = 5;
|
||||
i = git_array_alloc(integers); *i = 7;
|
||||
i = git_array_alloc(integers); *i = 7;
|
||||
i = git_array_alloc(integers); *i = 8;
|
||||
i = git_array_alloc(integers); *i = 13;
|
||||
i = git_array_alloc(integers); *i = 21;
|
||||
i = git_array_alloc(integers); *i = 25;
|
||||
i = git_array_alloc(integers); *i = 42;
|
||||
i = git_array_alloc(integers); *i = 69;
|
||||
i = git_array_alloc(integers); *i = 121;
|
||||
i = git_array_alloc(integers); *i = 256;
|
||||
i = git_array_alloc(integers); *i = 512;
|
||||
i = git_array_alloc(integers); *i = 513;
|
||||
i = git_array_alloc(integers); *i = 514;
|
||||
i = git_array_alloc(integers); *i = 516;
|
||||
i = git_array_alloc(integers); *i = 516;
|
||||
i = git_array_alloc(integers); *i = 517;
|
||||
|
||||
/* value to search for, expected position, return code */
|
||||
expect_pos(3, 1, GIT_OK);
|
||||
expect_pos(2, 0, GIT_OK);
|
||||
expect_pos(1, 0, GIT_ENOTFOUND);
|
||||
expect_pos(25, 8, GIT_OK);
|
||||
expect_pos(26, 9, GIT_ENOTFOUND);
|
||||
expect_pos(42, 9, GIT_OK);
|
||||
expect_pos(50, 10, GIT_ENOTFOUND);
|
||||
expect_pos(68, 10, GIT_ENOTFOUND);
|
||||
expect_pos(256, 12, GIT_OK);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user