Merge branch 'jk/stable-prio-queue'

* jk/stable-prio-queue:
  t5539: update a flaky test
  paint_down_to_common: use prio_queue
  prio-queue: make output stable with respect to insertion
  prio-queue: factor out compare and swap operations
This commit is contained in:
Junio C Hamano 2014-07-27 15:14:14 -07:00
commit 4799593e26
4 changed files with 60 additions and 51 deletions

View file

@ -764,45 +764,41 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
static struct commit *interesting(struct commit_list *list)
static int queue_has_nonstale(struct prio_queue *queue)
{
while (list) {
struct commit *commit = list->item;
list = list->next;
if (commit->object.flags & STALE)
continue;
return commit;
int i;
for (i = 0; i < queue->nr; i++) {
struct commit *commit = queue->array[i].data;
if (!(commit->object.flags & STALE))
return 1;
}
return NULL;
return 0;
}
/* all input commits in one and twos[] must have been parsed! */
static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
{
struct commit_list *list = NULL;
struct prio_queue queue = { compare_commits_by_commit_date };
struct commit_list *result = NULL;
int i;
one->object.flags |= PARENT1;
commit_list_insert_by_date(one, &list);
if (!n)
return list;
if (!n) {
commit_list_append(one, &result);
return result;
}
prio_queue_put(&queue, one);
for (i = 0; i < n; i++) {
twos[i]->object.flags |= PARENT2;
commit_list_insert_by_date(twos[i], &list);
prio_queue_put(&queue, twos[i]);
}
while (interesting(list)) {
struct commit *commit;
while (queue_has_nonstale(&queue)) {
struct commit *commit = prio_queue_get(&queue);
struct commit_list *parents;
struct commit_list *next;
int flags;
commit = list->item;
next = list->next;
free(list);
list = next;
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
if (flags == (PARENT1 | PARENT2)) {
if (!(commit->object.flags & RESULT)) {
@ -821,11 +817,11 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
if (parse_commit(p))
return NULL;
p->object.flags |= flags;
commit_list_insert_by_date(p, &list);
prio_queue_put(&queue, p);
}
}
free_commit_list(list);
clear_prio_queue(&queue);
return result;
}

View file

@ -1,18 +1,30 @@
#include "cache.h"
#include "commit.h"
#include "prio-queue.h"
static inline int compare(struct prio_queue *queue, int i, int j)
{
int cmp = queue->compare(queue->array[i].data, queue->array[j].data,
queue->cb_data);
if (!cmp)
cmp = queue->array[i].ctr - queue->array[j].ctr;
return cmp;
}
static inline void swap(struct prio_queue *queue, int i, int j)
{
struct prio_queue_entry tmp = queue->array[i];
queue->array[i] = queue->array[j];
queue->array[j] = tmp;
}
void prio_queue_reverse(struct prio_queue *queue)
{
int i, j;
if (queue->compare != NULL)
die("BUG: prio_queue_reverse() on non-LIFO queue");
for (i = 0; i <= (j = (queue->nr - 1) - i); i++) {
struct commit *swap = queue->array[i];
queue->array[i] = queue->array[j];
queue->array[j] = swap;
}
for (i = 0; i <= (j = (queue->nr - 1) - i); i++)
swap(queue, i, j);
}
void clear_prio_queue(struct prio_queue *queue)
@ -21,44 +33,42 @@ void clear_prio_queue(struct prio_queue *queue)
queue->nr = 0;
queue->alloc = 0;
queue->array = NULL;
queue->insertion_ctr = 0;
}
void prio_queue_put(struct prio_queue *queue, void *thing)
{
prio_queue_compare_fn compare = queue->compare;
int ix, parent;
/* Append at the end */
ALLOC_GROW(queue->array, queue->nr + 1, queue->alloc);
queue->array[queue->nr++] = thing;
if (!compare)
queue->array[queue->nr].ctr = queue->insertion_ctr++;
queue->array[queue->nr].data = thing;
queue->nr++;
if (!queue->compare)
return; /* LIFO */
/* Bubble up the new one */
for (ix = queue->nr - 1; ix; ix = parent) {
parent = (ix - 1) / 2;
if (compare(queue->array[parent], queue->array[ix],
queue->cb_data) <= 0)
if (compare(queue, parent, ix) <= 0)
break;
thing = queue->array[parent];
queue->array[parent] = queue->array[ix];
queue->array[ix] = thing;
swap(queue, parent, ix);
}
}
void *prio_queue_get(struct prio_queue *queue)
{
void *result, *swap;
void *result;
int ix, child;
prio_queue_compare_fn compare = queue->compare;
if (!queue->nr)
return NULL;
if (!compare)
return queue->array[--queue->nr]; /* LIFO */
if (!queue->compare)
return queue->array[--queue->nr].data; /* LIFO */
result = queue->array[0];
result = queue->array[0].data;
if (!--queue->nr)
return result;
@ -67,18 +77,14 @@ void *prio_queue_get(struct prio_queue *queue)
/* Push down the one at the root */
for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
child = ix * 2 + 1; /* left */
if ((child + 1 < queue->nr) &&
(compare(queue->array[child], queue->array[child + 1],
queue->cb_data) >= 0))
if (child + 1 < queue->nr &&
compare(queue, child, child + 1) >= 0)
child++; /* use right child */
if (compare(queue->array[ix], queue->array[child],
queue->cb_data) <= 0)
if (compare(queue, ix, child) <= 0)
break;
swap = queue->array[child];
queue->array[child] = queue->array[ix];
queue->array[ix] = swap;
swap(queue, child, ix);
}
return result;
}

View file

@ -21,11 +21,17 @@
*/
typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data);
struct prio_queue_entry {
unsigned ctr;
void *data;
};
struct prio_queue {
prio_queue_compare_fn compare;
unsigned insertion_ctr;
void *cb_data;
int alloc, nr;
void **array;
struct prio_queue_entry *array;
};
/*

View file

@ -54,6 +54,7 @@ EOF
test_expect_success 'no shallow lines after receiving ACK ready' '
(
cd shallow &&
test_tick &&
for i in $(test_seq 15)
do
git checkout --orphan unrelated$i &&