Skip to content

Commit 5ebcaaf

Browse files
committed
Merge branch 'rs/describe-with-prio-queue' into next
"git describe" has been optimized by using better data structure. * rs/describe-with-prio-queue: describe: use prio_queue_replace() describe: use prio_queue
2 parents 227d2fa + 08bb69d commit 5ebcaaf

File tree

1 file changed

+63
-24
lines changed

1 file changed

+63
-24
lines changed

builtin/describe.c

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "list-objects.h"
2424
#include "commit-slab.h"
2525
#include "wildmatch.h"
26+
#include "prio-queue.h"
2627

2728
#define MAX_TAGS (FLAG_BITS - 1)
2829
#define DEFAULT_CANDIDATES 10
@@ -249,32 +250,70 @@ static int compare_pt(const void *a_, const void *b_)
249250
return 0;
250251
}
251252

252-
static unsigned long finish_depth_computation(
253-
struct commit_list **list,
254-
struct possible_tag *best)
253+
struct lazy_queue {
254+
struct prio_queue queue;
255+
bool get_pending;
256+
};
257+
258+
#define LAZY_QUEUE_INIT { { compare_commits_by_commit_date }, false }
259+
260+
static void *lazy_queue_get(struct lazy_queue *queue)
261+
{
262+
if (queue->get_pending)
263+
prio_queue_get(&queue->queue);
264+
else
265+
queue->get_pending = true;
266+
return prio_queue_peek(&queue->queue);
267+
}
268+
269+
static void lazy_queue_put(struct lazy_queue *queue, void *thing)
270+
{
271+
if (queue->get_pending)
272+
prio_queue_replace(&queue->queue, thing);
273+
else
274+
prio_queue_put(&queue->queue, thing);
275+
queue->get_pending = false;
276+
}
277+
278+
static bool lazy_queue_empty(const struct lazy_queue *queue)
279+
{
280+
return queue->queue.nr == (queue->get_pending ? 1 : 0);
281+
}
282+
283+
static void lazy_queue_clear(struct lazy_queue *queue)
284+
{
285+
clear_prio_queue(&queue->queue);
286+
queue->get_pending = false;
287+
}
288+
289+
static bool all_have_flag(const struct lazy_queue *queue, unsigned flag)
290+
{
291+
for (size_t i = queue->get_pending ? 1 : 0; i < queue->queue.nr; i++) {
292+
struct commit *commit = queue->queue.array[i].data;
293+
if (!(commit->object.flags & flag))
294+
return false;
295+
}
296+
return true;
297+
}
298+
299+
static unsigned long finish_depth_computation(struct lazy_queue *queue,
300+
struct possible_tag *best)
255301
{
256302
unsigned long seen_commits = 0;
257-
while (*list) {
258-
struct commit *c = pop_commit(list);
303+
while (!lazy_queue_empty(queue)) {
304+
struct commit *c = lazy_queue_get(queue);
259305
struct commit_list *parents = c->parents;
260306
seen_commits++;
261307
if (c->object.flags & best->flag_within) {
262-
struct commit_list *a = *list;
263-
while (a) {
264-
struct commit *i = a->item;
265-
if (!(i->object.flags & best->flag_within))
266-
break;
267-
a = a->next;
268-
}
269-
if (!a)
308+
if (all_have_flag(queue, best->flag_within))
270309
break;
271310
} else
272311
best->depth++;
273312
while (parents) {
274313
struct commit *p = parents->item;
275314
repo_parse_commit(the_repository, p);
276315
if (!(p->object.flags & SEEN))
277-
commit_list_insert_by_date(p, list);
316+
lazy_queue_put(queue, p);
278317
p->object.flags |= c->object.flags;
279318
parents = parents->next;
280319
}
@@ -316,7 +355,7 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
316355
static void describe_commit(struct object_id *oid, struct strbuf *dst)
317356
{
318357
struct commit *cmit, *gave_up_on = NULL;
319-
struct commit_list *list;
358+
struct lazy_queue queue = LAZY_QUEUE_INIT;
320359
struct commit_name *n;
321360
struct possible_tag all_matches[MAX_TAGS];
322361
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
@@ -359,11 +398,10 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
359398
have_util = 1;
360399
}
361400

362-
list = NULL;
363401
cmit->object.flags = SEEN;
364-
commit_list_insert(cmit, &list);
365-
while (list) {
366-
struct commit *c = pop_commit(&list);
402+
lazy_queue_put(&queue, cmit);
403+
while (!lazy_queue_empty(&queue)) {
404+
struct commit *c = lazy_queue_get(&queue);
367405
struct commit_list *parents = c->parents;
368406
struct commit_name **slot;
369407

@@ -397,7 +435,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
397435
t->depth++;
398436
}
399437
/* Stop if last remaining path already covered by best candidate(s) */
400-
if (annotated_cnt && !list) {
438+
if (annotated_cnt && lazy_queue_empty(&queue)) {
401439
int best_depth = INT_MAX;
402440
unsigned best_within = 0;
403441
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
@@ -420,7 +458,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
420458
struct commit *p = parents->item;
421459
repo_parse_commit(the_repository, p);
422460
if (!(p->object.flags & SEEN))
423-
commit_list_insert_by_date(p, &list);
461+
lazy_queue_put(&queue, p);
424462
p->object.flags |= c->object.flags;
425463
parents = parents->next;
426464

@@ -435,6 +473,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
435473
strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
436474
if (suffix)
437475
strbuf_addstr(dst, suffix);
476+
lazy_queue_clear(&queue);
438477
return;
439478
}
440479
if (unannotated_cnt)
@@ -450,11 +489,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
450489
QSORT(all_matches, match_cnt, compare_pt);
451490

452491
if (gave_up_on) {
453-
commit_list_insert_by_date(gave_up_on, &list);
492+
lazy_queue_put(&queue, gave_up_on);
454493
seen_commits--;
455494
}
456-
seen_commits += finish_depth_computation(&list, &all_matches[0]);
457-
free_commit_list(list);
495+
seen_commits += finish_depth_computation(&queue, &all_matches[0]);
496+
lazy_queue_clear(&queue);
458497

459498
if (debug) {
460499
static int label_width = -1;

0 commit comments

Comments
 (0)