Skip to content

Commit 3d5091d

Browse files
rscharfegitster
authored andcommitted
prio-queue: add prio_queue_replace()
Add a function to replace the top element of the queue that basically does the same as prio_queue_get() followed by prio_queue_put(), but without the work by prio_queue_get() to rebalance the heap. It can be used to optimize loops that get one element and then immediately add another one. That's common e.g., with commit history traversal, where we get out a commit and then put in its parents. Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d6ec087 commit 3d5091d

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

prio-queue.c

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,10 @@ void prio_queue_put(struct prio_queue *queue, void *thing)
5858
}
5959
}
6060

61-
void *prio_queue_get(struct prio_queue *queue)
61+
static void sift_down_root(struct prio_queue *queue)
6262
{
63-
void *result;
6463
size_t ix, child;
6564

66-
if (!queue->nr)
67-
return NULL;
68-
if (!queue->compare)
69-
return queue->array[--queue->nr].data; /* LIFO */
70-
71-
result = queue->array[0].data;
72-
if (!--queue->nr)
73-
return result;
74-
75-
queue->array[0] = queue->array[queue->nr];
76-
7765
/* Push down the one at the root */
7866
for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
7967
child = ix * 2 + 1; /* left */
@@ -86,6 +74,23 @@ void *prio_queue_get(struct prio_queue *queue)
8674

8775
swap(queue, child, ix);
8876
}
77+
}
78+
79+
void *prio_queue_get(struct prio_queue *queue)
80+
{
81+
void *result;
82+
83+
if (!queue->nr)
84+
return NULL;
85+
if (!queue->compare)
86+
return queue->array[--queue->nr].data; /* LIFO */
87+
88+
result = queue->array[0].data;
89+
if (!--queue->nr)
90+
return result;
91+
92+
queue->array[0] = queue->array[queue->nr];
93+
sift_down_root(queue);
8994
return result;
9095
}
9196

@@ -97,3 +102,17 @@ void *prio_queue_peek(struct prio_queue *queue)
97102
return queue->array[queue->nr - 1].data;
98103
return queue->array[0].data;
99104
}
105+
106+
void prio_queue_replace(struct prio_queue *queue, void *thing)
107+
{
108+
if (!queue->nr) {
109+
prio_queue_put(queue, thing);
110+
} else if (!queue->compare) {
111+
queue->array[queue->nr - 1].ctr = queue->insertion_ctr++;
112+
queue->array[queue->nr - 1].data = thing;
113+
} else {
114+
queue->array[0].ctr = queue->insertion_ctr++;
115+
queue->array[0].data = thing;
116+
sift_down_root(queue);
117+
}
118+
}

prio-queue.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ void *prio_queue_get(struct prio_queue *);
5252
*/
5353
void *prio_queue_peek(struct prio_queue *);
5454

55+
/*
56+
* Replace the "thing" that compares the smallest with a new "thing",
57+
* like prio_queue_get()+prio_queue_put() would do, but in a more
58+
* efficient way. Does the same as prio_queue_put() if the queue is
59+
* empty.
60+
*/
61+
void prio_queue_replace(struct prio_queue *queue, void *thing);
62+
5563
void clear_prio_queue(struct prio_queue *);
5664

5765
/* Reverse the LIFO elements */

t/unit-tests/u-prio-queue.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ static int intcmp(const void *va, const void *vb, void *data UNUSED)
1313
#define STACK -3
1414
#define GET -4
1515
#define REVERSE -5
16+
#define REPLACE -6
1617

1718
static int show(int *v)
1819
{
@@ -51,6 +52,15 @@ static void test_prio_queue(int *input, size_t input_size,
5152
case REVERSE:
5253
prio_queue_reverse(&pq);
5354
break;
55+
case REPLACE:
56+
peek = prio_queue_peek(&pq);
57+
cl_assert(i + 1 < input_size);
58+
cl_assert(input[i + 1] >= 0);
59+
cl_assert(j < result_size);
60+
cl_assert_equal_i(result[j], show(peek));
61+
j++;
62+
prio_queue_replace(&pq, &input[++i]);
63+
break;
5464
default:
5565
prio_queue_put(&pq, &input[i]);
5666
break;
@@ -81,6 +91,13 @@ void test_prio_queue__empty(void)
8191
((int []){ 1, 2, MISSING, 1, 2, MISSING }));
8292
}
8393

94+
void test_prio_queue__replace(void)
95+
{
96+
TEST_INPUT(((int []){ REPLACE, 6, 2, 4, REPLACE, 5, 7, GET,
97+
REPLACE, 1, DUMP }),
98+
((int []){ MISSING, 2, 4, 5, 1, 6, 7 }));
99+
}
100+
84101
void test_prio_queue__stack(void)
85102
{
86103
TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }),
@@ -92,3 +109,9 @@ void test_prio_queue__reverse_stack(void)
92109
TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }),
93110
((int []){ 1, 2, 3, 4, 5, 6 }));
94111
}
112+
113+
void test_prio_queue__replace_stack(void)
114+
{
115+
TEST_INPUT(((int []){ STACK, 8, 1, 5, REPLACE, 4, 6, 2, 3, DUMP }),
116+
((int []){ 5, 3, 2, 6, 4, 1, 8 }));
117+
}

0 commit comments

Comments
 (0)