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>
This commit is contained in:
parent
8738a8a4df
commit
157113c614
@ -287,6 +287,20 @@ struct prefix_ref_iterator {
|
|||||||
int trim;
|
int trim;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Return -1, 0, 1 if refname is before, inside, or after the prefix. */
|
||||||
|
static int compare_prefix(const char *refname, const char *prefix)
|
||||||
|
{
|
||||||
|
while (*prefix) {
|
||||||
|
if (*refname != *prefix)
|
||||||
|
return ((unsigned char)*refname < (unsigned char)*prefix) ? -1 : +1;
|
||||||
|
|
||||||
|
refname++;
|
||||||
|
prefix++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
||||||
{
|
{
|
||||||
struct prefix_ref_iterator *iter =
|
struct prefix_ref_iterator *iter =
|
||||||
@ -294,9 +308,25 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
|||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
|
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
|
||||||
if (!starts_with(iter->iter0->refname, iter->prefix))
|
int cmp = compare_prefix(iter->iter0->refname, iter->prefix);
|
||||||
|
|
||||||
|
if (cmp < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (cmp > 0) {
|
||||||
|
/*
|
||||||
|
* If the source iterator is ordered, then we
|
||||||
|
* can stop the iteration as soon as we see a
|
||||||
|
* refname that comes after the prefix:
|
||||||
|
*/
|
||||||
|
if (iter->iter0->ordered) {
|
||||||
|
ok = ref_iterator_abort(iter->iter0);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (iter->trim) {
|
if (iter->trim) {
|
||||||
/*
|
/*
|
||||||
* It is nonsense to trim off characters that
|
* It is nonsense to trim off characters that
|
||||||
|
Loading…
Reference in New Issue
Block a user