Commit 882c7742 by Russell Belfer

Convert pqueue to just be a git_vector

This updates the git_pqueue to simply be a set of specialized
init/insert/pop functions on a git_vector.

To preserve the pqueue feature of having a fixed size heap, I
converted the "sorted" field in git_vectors to a more general
"flags" field so that pqueue could mix in it's own flag.  This
had a bunch of ramifications because a number of places were
directly looking at the vector "sorted" field - I added a couple
new git_vector helpers (is_sorted, set_sorted) so the specific
representation of this information could be abstracted.
parent af4bc661
...@@ -1564,7 +1564,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) ...@@ -1564,7 +1564,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
} }
/* entries are guaranteed to be sorted on-disk */ /* entries are guaranteed to be sorted on-disk */
index->reuc.sorted = 1; git_vector_set_sorted(&index->reuc, true);
return 0; return 0;
} }
...@@ -1610,7 +1610,7 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size ...@@ -1610,7 +1610,7 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
#undef read_conflict_name #undef read_conflict_name
/* entries are guaranteed to be sorted on-disk */ /* entries are guaranteed to be sorted on-disk */
index->names.sorted = 1; git_vector_set_sorted(&index->names, true);
return 0; return 0;
} }
...@@ -1812,7 +1812,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) ...@@ -1812,7 +1812,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
#undef seek_forward #undef seek_forward
/* Entries are stored case-sensitively on disk. */ /* Entries are stored case-sensitively on disk. */
index->entries.sorted = !index->ignore_case; git_vector_set_sorted(&index->entries, index->ignore_case);
git_vector_sort(&index->entries); git_vector_sort(&index->entries);
return 0; return 0;
......
...@@ -15,25 +15,29 @@ ...@@ -15,25 +15,29 @@
int git_pqueue_init( int git_pqueue_init(
git_pqueue *pq, git_pqueue *pq,
uint32_t flags, uint32_t flags,
size_t est_size, size_t init_size,
git_vector_cmp cmp) git_vector_cmp cmp)
{ {
pq->flags = flags; int error = git_vector_init(pq, init_size, cmp);
pq->initial_size = est_size;
return git_vector_init(&pq->values, est_size, cmp);
}
void git_pqueue_free(git_pqueue *pq) if (!error) {
{ /* mix in our flags */
git_vector_free(&pq->values); pq->flags |= flags;
/* if fixed size heap, pretend vector is exactly init_size elements */
if ((flags & GIT_PQUEUE_FIXED_SIZE) && init_size > 0)
pq->_alloc_size = init_size;
}
return error;
} }
static void pqueue_up(git_pqueue *pq, size_t el) static void pqueue_up(git_pqueue *pq, size_t el)
{ {
size_t parent_el = PQUEUE_PARENT_OF(el); size_t parent_el = PQUEUE_PARENT_OF(el);
while (el > 0 && git_vector_cmp_elements(&pq->values, parent_el, el) > 0) { while (el > 0 && git_vector_cmp_elements(pq, parent_el, el) > 0) {
git_vector_swap_elements(&pq->values, el, parent_el); git_vector_swap_elements(pq, el, parent_el);
el = parent_el; el = parent_el;
parent_el = PQUEUE_PARENT_OF(el); parent_el = PQUEUE_PARENT_OF(el);
...@@ -42,19 +46,19 @@ static void pqueue_up(git_pqueue *pq, size_t el) ...@@ -42,19 +46,19 @@ static void pqueue_up(git_pqueue *pq, size_t el)
static void pqueue_down(git_pqueue *pq, size_t el) static void pqueue_down(git_pqueue *pq, size_t el)
{ {
size_t last = git_vector_length(&pq->values); size_t last = git_pqueue_size(pq);
while (1) { while (1) {
size_t kid = PQUEUE_LCHILD_OF(el), rkid = PQUEUE_RCHILD_OF(el); size_t kid = PQUEUE_LCHILD_OF(el), rkid = PQUEUE_RCHILD_OF(el);
if (kid >= last) if (kid >= last)
break; break;
if (rkid < last && git_vector_cmp_elements(&pq->values, kid, rkid) > 0) if (rkid < last && git_vector_cmp_elements(pq, kid, rkid) > 0)
kid = rkid; kid = rkid;
if (git_vector_cmp_elements(&pq->values, el, kid) < 0) if (git_vector_cmp_elements(pq, el, kid) < 0)
break; break;
git_vector_swap_elements(&pq->values, el, kid); git_vector_swap_elements(pq, el, kid);
el = kid; el = kid;
} }
} }
...@@ -65,32 +69,33 @@ int git_pqueue_insert(git_pqueue *pq, void *item) ...@@ -65,32 +69,33 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
/* if heap is full, pop the top element if new one should replace it */ /* if heap is full, pop the top element if new one should replace it */
if ((pq->flags & GIT_PQUEUE_FIXED_SIZE) != 0 && if ((pq->flags & GIT_PQUEUE_FIXED_SIZE) != 0 &&
pq->values.length >= pq->initial_size) pq->length >= pq->_alloc_size)
{ {
/* skip item if below min item in heap */ /* skip this item if below min item in heap */
if (pq->values._cmp(item, git_vector_get(&pq->values, 0)) <= 0) if (pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
return 0; return 0;
/* otherwise remove the min item before inserting new */
(void)git_pqueue_pop(pq); (void)git_pqueue_pop(pq);
} }
error = git_vector_insert(&pq->values, item); if (!(error = git_vector_insert(pq, item)))
pqueue_up(pq, pq->length - 1);
if (!error)
pqueue_up(pq, pq->values.length - 1);
return error; return error;
} }
void *git_pqueue_pop(git_pqueue *pq) void *git_pqueue_pop(git_pqueue *pq)
{ {
void *rval = git_vector_get(&pq->values, 0); void *rval = git_pqueue_get(pq, 0);
if (git_vector_length(&pq->values) > 1) { if (git_pqueue_size(pq) > 1) {
pq->values.contents[0] = git_vector_last(&pq->values); /* move last item to top of heap, shrink, and push item down */
git_vector_pop(&pq->values); pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq);
pqueue_down(pq, 0); pqueue_down(pq, 0);
} else { } else {
git_vector_pop(&pq->values); /* all we need to do is shrink the heap in this case */
git_vector_pop(pq);
} }
return rval; return rval;
......
...@@ -9,15 +9,11 @@ ...@@ -9,15 +9,11 @@
#include "vector.h" #include "vector.h"
typedef struct { typedef git_vector git_pqueue;
git_vector values;
size_t initial_size;
uint32_t flags;
} git_pqueue;
enum { enum {
GIT_PQUEUE_DEFAULT = 0, /* flag meaning: don't grow heap, keep highest values only */
GIT_PQUEUE_FIXED_SIZE = (1 << 0), /* don't grow heap, keep highest */ GIT_PQUEUE_FIXED_SIZE = (GIT_VECTOR_FLAG_MAX << 1),
}; };
/** /**
...@@ -25,36 +21,20 @@ enum { ...@@ -25,36 +21,20 @@ enum {
* *
* @param pq The priority queue struct to initialize * @param pq The priority queue struct to initialize
* @param flags Flags (see above) to control queue behavior * @param flags Flags (see above) to control queue behavior
* @param est_size The estimated/initial queue size * @param init_size The initial queue size
* @param cmp The entry priority comparison function * @param cmp The entry priority comparison function
* @return 0 on success, <0 on error * @return 0 on success, <0 on error
*/ */
extern int git_pqueue_init( extern int git_pqueue_init(
git_pqueue *pq, git_pqueue *pq,
uint32_t flags, uint32_t flags,
size_t est_size, size_t init_size,
git_vector_cmp cmp); git_vector_cmp cmp);
/** #define git_pqueue_free git_vector_free
* Free the queue memory #define git_pqueue_clear git_vector_clear
*/ #define git_pqueue_size git_vector_length
extern void git_pqueue_free(git_pqueue *pq); #define git_pqueue_get git_vector_get
/**
* Get the number of items in the queue
*/
GIT_INLINE(size_t) git_pqueue_size(const git_pqueue *pq)
{
return git_vector_length(&pq->values);
}
/**
* Get an item in the queue
*/
GIT_INLINE(void *) git_pqueue_get(const git_pqueue *pq, size_t pos)
{
return git_vector_get(&pq->values, pos);
}
/** /**
* Insert a new item into the queue * Insert a new item into the queue
......
...@@ -543,7 +543,7 @@ void git_revwalk_reset(git_revwalk *walk) ...@@ -543,7 +543,7 @@ void git_revwalk_reset(git_revwalk *walk)
commit->uninteresting = 0; commit->uninteresting = 0;
}); });
git_pqueue_free(&walk->iterator_time); git_pqueue_clear(&walk->iterator_time);
git_commit_list_free(&walk->iterator_topo); git_commit_list_free(&walk->iterator_topo);
git_commit_list_free(&walk->iterator_rand); git_commit_list_free(&walk->iterator_rand);
git_commit_list_free(&walk->iterator_reverse); git_commit_list_free(&walk->iterator_reverse);
......
...@@ -321,7 +321,7 @@ size_t git_sortedcache_entrycount(const git_sortedcache *sc) ...@@ -321,7 +321,7 @@ size_t git_sortedcache_entrycount(const git_sortedcache *sc)
void *git_sortedcache_entry(git_sortedcache *sc, size_t pos) void *git_sortedcache_entry(git_sortedcache *sc, size_t pos)
{ {
/* make sure the items are sorted so this gets the correct item */ /* make sure the items are sorted so this gets the correct item */
if (!sc->items.sorted) if (!git_vector_is_sorted(&sc->items))
git_vector_sort(&sc->items); git_vector_sort(&sc->items);
return git_vector_get(&sc->items, pos); return git_vector_get(&sc->items, pos);
......
...@@ -283,7 +283,8 @@ static const git_tree_entry *entry_fromname( ...@@ -283,7 +283,8 @@ static const git_tree_entry *entry_fromname(
{ {
size_t idx; size_t idx;
assert(tree->entries.sorted); /* be safe when we cast away constness */ /* 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, (git_vector *)&tree->entries, name, name_len) < 0)
return NULL; return NULL;
...@@ -333,7 +334,8 @@ int git_tree__prefix_position(const git_tree *tree, const char *path) ...@@ -333,7 +334,8 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
ksearch.filename = path; ksearch.filename = path;
ksearch.filename_len = strlen(path); ksearch.filename_len = strlen(path);
assert(tree->entries.sorted); /* be safe when we cast away constness */ /* 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 */ /* Find tree entry with appropriate prefix */
git_vector_bsearch2( git_vector_bsearch2(
......
...@@ -56,7 +56,9 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) ...@@ -56,7 +56,9 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
v->_alloc_size = src->length; v->_alloc_size = src->length;
v->_cmp = cmp; v->_cmp = cmp;
v->length = src->length; v->length = src->length;
v->sorted = src->sorted && cmp == src->_cmp; v->flags = src->flags;
if (cmp != src->_cmp)
git_vector_set_sorted(v, 0);
v->contents = git__malloc(bytes); v->contents = git__malloc(bytes);
GITERR_CHECK_ALLOC(v->contents); GITERR_CHECK_ALLOC(v->contents);
...@@ -97,7 +99,7 @@ int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) ...@@ -97,7 +99,7 @@ int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
v->_alloc_size = 0; v->_alloc_size = 0;
v->_cmp = cmp; v->_cmp = cmp;
v->length = 0; v->length = 0;
v->sorted = 1; v->flags = GIT_VECTOR_SORTED;
v->contents = NULL; v->contents = NULL;
return resize_vector(v, max(initial_size, MIN_ALLOCSIZE)); return resize_vector(v, max(initial_size, MIN_ALLOCSIZE));
...@@ -128,7 +130,8 @@ int git_vector_insert(git_vector *v, void *element) ...@@ -128,7 +130,8 @@ int git_vector_insert(git_vector *v, void *element)
return -1; return -1;
v->contents[v->length++] = element; v->contents[v->length++] = element;
v->sorted = 0;
git_vector_set_sorted(v, v->length <= 1);
return 0; return 0;
} }
...@@ -141,7 +144,7 @@ int git_vector_insert_sorted( ...@@ -141,7 +144,7 @@ int git_vector_insert_sorted(
assert(v && v->_cmp); assert(v && v->_cmp);
if (!v->sorted) if (!git_vector_is_sorted(v))
git_vector_sort(v); git_vector_sort(v);
if (v->length >= v->_alloc_size && if (v->length >= v->_alloc_size &&
...@@ -171,11 +174,11 @@ void git_vector_sort(git_vector *v) ...@@ -171,11 +174,11 @@ void git_vector_sort(git_vector *v)
{ {
assert(v); assert(v);
if (v->sorted || !v->_cmp) if (git_vector_is_sorted(v) || !v->_cmp)
return; return;
git__tsort(v->contents, v->length, v->_cmp); git__tsort(v->contents, v->length, v->_cmp);
v->sorted = 1; git_vector_set_sorted(v, 1);
} }
int git_vector_bsearch2( int git_vector_bsearch2(
...@@ -291,7 +294,7 @@ void git_vector_clear(git_vector *v) ...@@ -291,7 +294,7 @@ void git_vector_clear(git_vector *v)
{ {
assert(v); assert(v);
v->length = 0; v->length = 0;
v->sorted = 1; git_vector_set_sorted(v, 1);
} }
void git_vector_swap(git_vector *a, git_vector *b) void git_vector_swap(git_vector *a, git_vector *b)
......
...@@ -11,12 +11,17 @@ ...@@ -11,12 +11,17 @@
typedef int (*git_vector_cmp)(const void *, const void *); typedef int (*git_vector_cmp)(const void *, const void *);
enum {
GIT_VECTOR_SORTED = (1u << 0),
GIT_VECTOR_FLAG_MAX = (1u << 1),
};
typedef struct git_vector { typedef struct git_vector {
size_t _alloc_size; size_t _alloc_size;
git_vector_cmp _cmp; git_vector_cmp _cmp;
void **contents; void **contents;
size_t length; size_t length;
int sorted; uint32_t flags;
} git_vector; } git_vector;
#define GIT_VECTOR_INIT {0} #define GIT_VECTOR_INIT {0}
...@@ -86,12 +91,20 @@ void git_vector_remove_matching( ...@@ -86,12 +91,20 @@ void git_vector_remove_matching(
int git_vector_resize_to(git_vector *v, size_t new_length); int git_vector_resize_to(git_vector *v, size_t new_length);
int git_vector_set(void **old, git_vector *v, size_t position, void *value); int git_vector_set(void **old, git_vector *v, size_t position, void *value);
/** Check if vector is sorted */
#define git_vector_is_sorted(V) (((V)->flags & GIT_VECTOR_SORTED) != 0)
/** Directly set sorted state of vector */
#define git_vector_set_sorted(V,S) do { \
(V)->flags = (S) ? ((V)->flags | GIT_VECTOR_SORTED) : \
((V)->flags & ~GIT_VECTOR_SORTED); } while (0)
/** Set the comparison function used for sorting the vector */ /** Set the comparison function used for sorting the vector */
GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
{ {
if (cmp != v->_cmp) { if (cmp != v->_cmp) {
v->_cmp = cmp; v->_cmp = cmp;
v->sorted = 0; git_vector_set_sorted(v, 0);
} }
} }
......
...@@ -80,7 +80,7 @@ void test_index_tests__empty_index(void) ...@@ -80,7 +80,7 @@ void test_index_tests__empty_index(void)
cl_assert(index->on_disk == 0); cl_assert(index->on_disk == 0);
cl_assert(git_index_entrycount(index) == 0); cl_assert(git_index_entrycount(index) == 0);
cl_assert(index->entries.sorted); cl_assert(git_vector_is_sorted(&index->entries));
git_index_free(index); git_index_free(index);
} }
...@@ -95,7 +95,7 @@ void test_index_tests__default_test_index(void) ...@@ -95,7 +95,7 @@ void test_index_tests__default_test_index(void)
cl_assert(index->on_disk); cl_assert(index->on_disk);
cl_assert(git_index_entrycount(index) == index_entry_count); cl_assert(git_index_entrycount(index) == index_entry_count);
cl_assert(index->entries.sorted); cl_assert(git_vector_is_sorted(&index->entries));
entries = (git_index_entry **)index->entries.contents; entries = (git_index_entry **)index->entries.contents;
...@@ -118,7 +118,7 @@ void test_index_tests__gitgit_index(void) ...@@ -118,7 +118,7 @@ void test_index_tests__gitgit_index(void)
cl_assert(index->on_disk); cl_assert(index->on_disk);
cl_assert(git_index_entrycount(index) == index_entry_count_2); cl_assert(git_index_entrycount(index) == index_entry_count_2);
cl_assert(index->entries.sorted); cl_assert(git_vector_is_sorted(&index->entries));
cl_assert(index->tree != NULL); cl_assert(index->tree != NULL);
git_index_free(index); git_index_free(index);
...@@ -195,7 +195,7 @@ void test_index_tests__sort1(void) ...@@ -195,7 +195,7 @@ void test_index_tests__sort1(void)
cl_git_pass(git_index_open(&index, "fake-index")); cl_git_pass(git_index_open(&index, "fake-index"));
/* FIXME: this test is slightly dumb */ /* FIXME: this test is slightly dumb */
cl_assert(index->entries.sorted); cl_assert(git_vector_is_sorted(&index->entries));
git_index_free(index); git_index_free(index);
} }
......
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