]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs/iterator: implement seeking for merged iterators
authorPatrick Steinhardt <ps@pks.im>
Wed, 12 Mar 2025 15:56:17 +0000 (16:56 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 12 Mar 2025 18:31:19 +0000 (11:31 -0700)
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>
refs/iterator.c

index ea4db59481d4693462f0fca3796b2efc7faf6df4..766d96e795c9b933923786fb5d6f4257aa6449b7 100644 (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;