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)
}
/* entries are guaranteed to be sorted on-disk */
index->reuc.sorted = 1;
git_vector_set_sorted(&index->reuc, true);
return 0;
}
......@@ -1610,7 +1610,7 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
#undef read_conflict_name
/* entries are guaranteed to be sorted on-disk */
index->names.sorted = 1;
git_vector_set_sorted(&index->names, true);
return 0;
}
......@@ -1812,7 +1812,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
#undef seek_forward
/* 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);
return 0;
......
......@@ -15,25 +15,29 @@
int git_pqueue_init(
git_pqueue *pq,
uint32_t flags,
size_t est_size,
size_t init_size,
git_vector_cmp cmp)
{
pq->flags = flags;
pq->initial_size = est_size;
return git_vector_init(&pq->values, est_size, cmp);
}
int error = git_vector_init(pq, init_size, cmp);
void git_pqueue_free(git_pqueue *pq)
{
git_vector_free(&pq->values);
if (!error) {
/* mix in our flags */
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)
{
size_t parent_el = PQUEUE_PARENT_OF(el);
while (el > 0 && git_vector_cmp_elements(&pq->values, parent_el, el) > 0) {
git_vector_swap_elements(&pq->values, el, parent_el);
while (el > 0 && git_vector_cmp_elements(pq, parent_el, el) > 0) {
git_vector_swap_elements(pq, el, parent_el);
el = parent_el;
parent_el = PQUEUE_PARENT_OF(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)
{
size_t last = git_vector_length(&pq->values);
size_t last = git_pqueue_size(pq);
while (1) {
size_t kid = PQUEUE_LCHILD_OF(el), rkid = PQUEUE_RCHILD_OF(el);
if (kid >= last)
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;
if (git_vector_cmp_elements(&pq->values, el, kid) < 0)
if (git_vector_cmp_elements(pq, el, kid) < 0)
break;
git_vector_swap_elements(&pq->values, el, kid);
git_vector_swap_elements(pq, el, kid);
el = kid;
}
}
......@@ -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 ((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 */
if (pq->values._cmp(item, git_vector_get(&pq->values, 0)) <= 0)
/* skip this item if below min item in heap */
if (pq->_cmp(item, git_vector_get(pq, 0)) <= 0)
return 0;
/* otherwise remove the min item before inserting new */
(void)git_pqueue_pop(pq);
}
error = git_vector_insert(&pq->values, item);
if (!error)
pqueue_up(pq, pq->values.length - 1);
if (!(error = git_vector_insert(pq, item)))
pqueue_up(pq, pq->length - 1);
return error;
}
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) {
pq->values.contents[0] = git_vector_last(&pq->values);
git_vector_pop(&pq->values);
if (git_pqueue_size(pq) > 1) {
/* move last item to top of heap, shrink, and push item down */
pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq);
pqueue_down(pq, 0);
} else {
git_vector_pop(&pq->values);
/* all we need to do is shrink the heap in this case */
git_vector_pop(pq);
}
return rval;
......
......@@ -9,15 +9,11 @@
#include "vector.h"
typedef struct {
git_vector values;
size_t initial_size;
uint32_t flags;
} git_pqueue;
typedef git_vector git_pqueue;
enum {
GIT_PQUEUE_DEFAULT = 0,
GIT_PQUEUE_FIXED_SIZE = (1 << 0), /* don't grow heap, keep highest */
/* flag meaning: don't grow heap, keep highest values only */
GIT_PQUEUE_FIXED_SIZE = (GIT_VECTOR_FLAG_MAX << 1),
};
/**
......@@ -25,36 +21,20 @@ enum {
*
* @param pq The priority queue struct to initialize
* @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
* @return 0 on success, <0 on error
*/
extern int git_pqueue_init(
git_pqueue *pq,
uint32_t flags,
size_t est_size,
size_t init_size,
git_vector_cmp cmp);
/**
* Free the queue memory
*/
extern void git_pqueue_free(git_pqueue *pq);
/**
* 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);
}
#define git_pqueue_free git_vector_free
#define git_pqueue_clear git_vector_clear
#define git_pqueue_size git_vector_length
#define git_pqueue_get git_vector_get
/**
* Insert a new item into the queue
......
......@@ -543,7 +543,7 @@ void git_revwalk_reset(git_revwalk *walk)
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_rand);
git_commit_list_free(&walk->iterator_reverse);
......
......@@ -321,7 +321,7 @@ size_t git_sortedcache_entrycount(const git_sortedcache *sc)
void *git_sortedcache_entry(git_sortedcache *sc, size_t pos)
{
/* 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);
return git_vector_get(&sc->items, pos);
......
......@@ -283,7 +283,8 @@ static const git_tree_entry *entry_fromname(
{
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)
return NULL;
......@@ -333,7 +334,8 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
ksearch.filename = 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 */
git_vector_bsearch2(
......
......@@ -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->_cmp = cmp;
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);
GITERR_CHECK_ALLOC(v->contents);
......@@ -97,7 +99,7 @@ int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
v->_alloc_size = 0;
v->_cmp = cmp;
v->length = 0;
v->sorted = 1;
v->flags = GIT_VECTOR_SORTED;
v->contents = NULL;
return resize_vector(v, max(initial_size, MIN_ALLOCSIZE));
......@@ -128,7 +130,8 @@ int git_vector_insert(git_vector *v, void *element)
return -1;
v->contents[v->length++] = element;
v->sorted = 0;
git_vector_set_sorted(v, v->length <= 1);
return 0;
}
......@@ -141,7 +144,7 @@ int git_vector_insert_sorted(
assert(v && v->_cmp);
if (!v->sorted)
if (!git_vector_is_sorted(v))
git_vector_sort(v);
if (v->length >= v->_alloc_size &&
......@@ -171,11 +174,11 @@ void git_vector_sort(git_vector *v)
{
assert(v);
if (v->sorted || !v->_cmp)
if (git_vector_is_sorted(v) || !v->_cmp)
return;
git__tsort(v->contents, v->length, v->_cmp);
v->sorted = 1;
git_vector_set_sorted(v, 1);
}
int git_vector_bsearch2(
......@@ -291,7 +294,7 @@ void git_vector_clear(git_vector *v)
{
assert(v);
v->length = 0;
v->sorted = 1;
git_vector_set_sorted(v, 1);
}
void git_vector_swap(git_vector *a, git_vector *b)
......
......@@ -11,12 +11,17 @@
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 {
size_t _alloc_size;
git_vector_cmp _cmp;
void **contents;
size_t length;
int sorted;
uint32_t flags;
} git_vector;
#define GIT_VECTOR_INIT {0}
......@@ -86,12 +91,20 @@ void git_vector_remove_matching(
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);
/** 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 */
GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
{
if (cmp != v->_cmp) {
v->_cmp = cmp;
v->sorted = 0;
git_vector_set_sorted(v, 0);
}
}
......
......@@ -80,7 +80,7 @@ void test_index_tests__empty_index(void)
cl_assert(index->on_disk == 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);
}
......@@ -95,7 +95,7 @@ void test_index_tests__default_test_index(void)
cl_assert(index->on_disk);
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;
......@@ -118,7 +118,7 @@ void test_index_tests__gitgit_index(void)
cl_assert(index->on_disk);
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);
git_index_free(index);
......@@ -195,7 +195,7 @@ void test_index_tests__sort1(void)
cl_git_pass(git_index_open(&index, "fake-index"));
/* FIXME: this test is slightly dumb */
cl_assert(index->entries.sorted);
cl_assert(git_vector_is_sorted(&index->entries));
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