Skip to content

Commit 157113c

Browse files
peffgitster
authored andcommitted
prefix_ref_iterator: break when we leave the prefix
If the underlying iterator is ordered, then `prefix_ref_iterator` can stop as soon as it sees a refname that comes after the prefix. This will rarely make a big difference now, because `ref_cache_iterator` only iterates over the directory containing the prefix (and usually the prefix will span a whole directory anyway). But if *hint, hint* a future reference backend doesn't itself know where to stop the iteration, then this optimization will be a big win. Note that there is no guarantee that the underlying iterator doesn't include output preceding the prefix, so we have to skip over any unwanted references before we get to the ones that we want. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 8738a8a commit 157113c

1 file changed

Lines changed: 31 additions & 1 deletion

File tree

refs/iterator.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,46 @@ struct prefix_ref_iterator {
287287
int trim;
288288
};
289289

290+
/* Return -1, 0, 1 if refname is before, inside, or after the prefix. */
291+
static int compare_prefix(const char *refname, const char *prefix)
292+
{
293+
while (*prefix) {
294+
if (*refname != *prefix)
295+
return ((unsigned char)*refname < (unsigned char)*prefix) ? -1 : +1;
296+
297+
refname++;
298+
prefix++;
299+
}
300+
301+
return 0;
302+
}
303+
290304
static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
291305
{
292306
struct prefix_ref_iterator *iter =
293307
(struct prefix_ref_iterator *)ref_iterator;
294308
int ok;
295309

296310
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
297-
if (!starts_with(iter->iter0->refname, iter->prefix))
311+
int cmp = compare_prefix(iter->iter0->refname, iter->prefix);
312+
313+
if (cmp < 0)
298314
continue;
299315

316+
if (cmp > 0) {
317+
/*
318+
* If the source iterator is ordered, then we
319+
* can stop the iteration as soon as we see a
320+
* refname that comes after the prefix:
321+
*/
322+
if (iter->iter0->ordered) {
323+
ok = ref_iterator_abort(iter->iter0);
324+
break;
325+
} else {
326+
continue;
327+
}
328+
}
329+
300330
if (iter->trim) {
301331
/*
302332
* It is nonsense to trim off characters that

0 commit comments

Comments
 (0)