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>
Patrick Steinhardt committed
Mar 12, 2025 at 16:56 UTC
9821d90f13c6442022bbbcb2d96f1b29aad76503
1 file changed
+29
-9
refs/iterator.c
+29
-9
@@ -96,7 +96,8 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator)
96
struct merge_ref_iterator {
97
struct ref_iterator base;
98
99
- struct ref_iterator *iter0, *iter1;
99
+ struct ref_iterator *iter0, *iter0_owned;
100
+ struct ref_iterator *iter1, *iter1_owned;
101
102
ref_iterator_select_fn *select;
103
void *cb_data;
@@ -160,13 +161,11 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
161
if (!iter->current) {
162
/* Initialize: advance both iterators to their first entries */
163
if ((ok = ref_iterator_advance(iter->iter0)) != ITER_OK) {
163
- ref_iterator_free(iter->iter0);
164
iter->iter0 = NULL;
165
if (ok == ITER_ERROR)
166
goto error;
167
}
168
if ((ok = ref_iterator_advance(iter->iter1)) != ITER_OK) {
169
- ref_iterator_free(iter->iter1);
169
iter->iter1 = NULL;
170
if (ok == ITER_ERROR)
171
goto error;
@@ -177,7 +176,6 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
176
* entry:
177
*/
178
if ((ok = ref_iterator_advance(*iter->current)) != ITER_OK) {
180
- ref_iterator_free(*iter->current);
179
*iter->current = NULL;
180
if (ok == ITER_ERROR)
181
goto error;
@@ -206,7 +204,6 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
204
205
if (selection & ITER_SKIP_SECONDARY) {
206
if ((ok = ref_iterator_advance(*secondary)) != ITER_OK) {
209
- ref_iterator_free(*secondary);
207
*secondary = NULL;
208
if (ok == ITER_ERROR)
209
goto error;
@@ -226,6 +223,28 @@ error:
223
return ITER_ERROR;
224
}
225
226
+static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
227
+ const char *prefix)
228
+{
229
+ struct merge_ref_iterator *iter =
230
+ (struct merge_ref_iterator *)ref_iterator;
231
+ int ret;
232
+
233
+ iter->current = NULL;
234
+ iter->iter0 = iter->iter0_owned;
235
+ iter->iter1 = iter->iter1_owned;
236
+
237
+ ret = ref_iterator_seek(iter->iter0, prefix);
238
+ if (ret < 0)
239
+ return ret;
240
+
241
+ ret = ref_iterator_seek(iter->iter1, prefix);
242
+ if (ret < 0)
243
+ return ret;
244
+
245
+ return 0;
246
+}
247
+
248
static int merge_ref_iterator_peel(struct ref_iterator *ref_iterator,
249
struct object_id *peeled)
250
{
@@ -242,12 +261,13 @@ static void merge_ref_iterator_release(struct ref_iterator *ref_iterator)
261
{
262
struct merge_ref_iterator *iter =
263
(struct merge_ref_iterator *)ref_iterator;
245
- ref_iterator_free(iter->iter0);
246
- ref_iterator_free(iter->iter1);
264
+ ref_iterator_free(iter->iter0_owned);
265
+ ref_iterator_free(iter->iter1_owned);
266
}
267
268
static struct ref_iterator_vtable merge_ref_iterator_vtable = {
269
.advance = merge_ref_iterator_advance,
270
+ .seek = merge_ref_iterator_seek,
271
.peel = merge_ref_iterator_peel,
272
.release = merge_ref_iterator_release,
273
};
@@ -268,8 +288,8 @@ struct ref_iterator *merge_ref_iterator_begin(
288
*/
289
290
base_ref_iterator_init(ref_iterator, &merge_ref_iterator_vtable);
271
- iter->iter0 = iter0;
272
- iter->iter1 = iter1;
291
+ iter->iter0 = iter->iter0_owned = iter0;
292
+ iter->iter1 = iter->iter1_owned = iter1;
293
iter->select = select;
294
iter->cb_data = cb_data;
295
iter->current = NULL;