refs/iterator: implement seeking for merged iterators

Implement seeking on merged iterators. The implementation is rather
straight forward, with the only exception that we must not deallocate
the underlying iterators once they have been exhausted.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
Patrick Steinhardt 2025-03-12 16:56:17 +01:00 committed by Junio C Hamano
parent 82c39c6055
commit 9821d90f13
1 changed files with 29 additions and 9 deletions

View File

@ -96,7 +96,8 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator)
struct merge_ref_iterator {
struct ref_iterator base;

struct ref_iterator *iter0, *iter1;
struct ref_iterator *iter0, *iter0_owned;
struct ref_iterator *iter1, *iter1_owned;

ref_iterator_select_fn *select;
void *cb_data;
@ -160,13 +161,11 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (!iter->current) {
/* Initialize: advance both iterators to their first entries */
if ((ok = ref_iterator_advance(iter->iter0)) != ITER_OK) {
ref_iterator_free(iter->iter0);
iter->iter0 = NULL;
if (ok == ITER_ERROR)
goto error;
}
if ((ok = ref_iterator_advance(iter->iter1)) != ITER_OK) {
ref_iterator_free(iter->iter1);
iter->iter1 = NULL;
if (ok == ITER_ERROR)
goto error;
@ -177,7 +176,6 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
* entry:
*/
if ((ok = ref_iterator_advance(*iter->current)) != ITER_OK) {
ref_iterator_free(*iter->current);
*iter->current = NULL;
if (ok == ITER_ERROR)
goto error;
@ -206,7 +204,6 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)

if (selection & ITER_SKIP_SECONDARY) {
if ((ok = ref_iterator_advance(*secondary)) != ITER_OK) {
ref_iterator_free(*secondary);
*secondary = NULL;
if (ok == ITER_ERROR)
goto error;
@ -226,6 +223,28 @@ error:
return ITER_ERROR;
}

static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
const char *prefix)
{
struct merge_ref_iterator *iter =
(struct merge_ref_iterator *)ref_iterator;
int ret;

iter->current = NULL;
iter->iter0 = iter->iter0_owned;
iter->iter1 = iter->iter1_owned;

ret = ref_iterator_seek(iter->iter0, prefix);
if (ret < 0)
return ret;

ret = ref_iterator_seek(iter->iter1, prefix);
if (ret < 0)
return ret;

return 0;
}

static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct object_id *peeled)
{
@ -242,12 +261,13 @@ static void merge_ref_iterator_release(struct ref_iterator *ref_iterator)
{
struct merge_ref_iterator *iter =
(struct merge_ref_iterator *)ref_iterator;
ref_iterator_free(iter->iter0);
ref_iterator_free(iter->iter1);
ref_iterator_free(iter->iter0_owned);
ref_iterator_free(iter->iter1_owned);
}

static struct ref_iterator_vtable merge_ref_iterator_vtable = {
.advance = merge_ref_iterator_advance,
.seek = merge_ref_iterator_seek,
.peel = merge_ref_iterator_peel,
.release = merge_ref_iterator_release,
};
@ -268,8 +288,8 @@ struct ref_iterator *merge_ref_iterator_begin(
*/

base_ref_iterator_init(ref_iterator, &merge_ref_iterator_vtable);
iter->iter0 = iter0;
iter->iter1 = iter1;
iter->iter0 = iter->iter0_owned = iter0;
iter->iter1 = iter->iter1_owned = iter1;
iter->select = select;
iter->cb_data = cb_data;
iter->current = NULL;