@@ -265,6 +265,90 @@ struct concat_iteratort
265
265
second_iteratort second_begin;
266
266
};
267
267
268
+ // / Zip two ranges to make a range of pairs.
269
+ // / On increment, both iterators are incremented.
270
+ // / Ends when the two ranges reach their ends.
271
+ // / Invariants are checking that one does not end before the other.
272
+ template <typename first_iteratort, typename second_iteratort>
273
+ struct zip_iteratort
274
+ {
275
+ public:
276
+ using difference_type = typename first_iteratort::difference_type;
277
+ using value_type = std::pair<
278
+ typename first_iteratort::value_type,
279
+ typename second_iteratort::value_type>;
280
+ using pointer = value_type *;
281
+ using reference = value_type &;
282
+ using iterator_category = std::forward_iterator_tag;
283
+
284
+ bool operator ==(const zip_iteratort &other) const
285
+ {
286
+ return first_begin == other.first_begin && first_end == other.first_end &&
287
+ second_begin == other.second_begin && second_end == other.second_end ;
288
+ }
289
+
290
+ bool operator !=(const zip_iteratort &other) const
291
+ {
292
+ return !(*this == other);
293
+ }
294
+
295
+ // / Preincrement operator
296
+ zip_iteratort &operator ++()
297
+ {
298
+ PRECONDITION (first_begin != first_end && second_begin != second_end);
299
+ ++first_begin;
300
+ ++second_begin;
301
+ INVARIANT (
302
+ (first_begin == first_end) == (second_begin == second_end),
303
+ " Zipped ranges should have the same size" );
304
+ current = first_begin != first_end
305
+ ? std::make_shared<value_type>(*first_begin, *second_begin)
306
+ : nullptr ;
307
+ return *this ;
308
+ }
309
+
310
+ // / Postincrement operator
311
+ const zip_iteratort operator ++(int )
312
+ {
313
+ zip_iteratort tmp (first_begin, first_end, second_begin, second_end);
314
+ this ->operator ++();
315
+ return tmp;
316
+ }
317
+
318
+ reference operator *() const
319
+ {
320
+ PRECONDITION (current != nullptr );
321
+ return *current;
322
+ }
323
+
324
+ pointer operator ->() const
325
+ {
326
+ return current.get ();
327
+ }
328
+
329
+ zip_iteratort (
330
+ first_iteratort _first_begin,
331
+ first_iteratort _first_end,
332
+ second_iteratort _second_begin,
333
+ second_iteratort _second_end)
334
+ : first_begin(std::move(_first_begin)),
335
+ first_end (std::move(_first_end)),
336
+ second_begin(std::move(_second_begin)),
337
+ second_end(std::move(_second_end))
338
+ {
339
+ PRECONDITION ((first_begin == first_end) == (second_begin == second_end));
340
+ if (first_begin != first_end)
341
+ current = util_make_unique<value_type>(*first_begin, *second_begin);
342
+ }
343
+
344
+ private:
345
+ first_iteratort first_begin;
346
+ first_iteratort first_end;
347
+ second_iteratort second_begin;
348
+ second_iteratort second_end;
349
+ std::shared_ptr<value_type> current = nullptr ;
350
+ };
351
+
268
352
// / A range is a pair of a begin and an end iterators.
269
353
// / The class provides useful methods such as map, filter and concat which only
270
354
// / manipulate iterators and thus don't have to create instances of heavy data
@@ -337,6 +421,26 @@ struct ranget final
337
421
concat_begin, concat_end);
338
422
}
339
423
424
+ template <typename other_iteratort>
425
+ ranget<zip_iteratort<iteratort, other_iteratort>>
426
+ zip (ranget<other_iteratort> other)
427
+ {
428
+ auto zip_begin = zip_iteratort<iteratort, other_iteratort>(
429
+ begin (), end (), other.begin (), other.end ());
430
+ auto zip_end = zip_iteratort<iteratort, other_iteratort>(
431
+ end (), end (), other.end (), other.end ());
432
+ return ranget<zip_iteratort<iteratort, other_iteratort>>(
433
+ zip_begin, zip_end);
434
+ }
435
+
436
+ template <typename containert>
437
+ auto zip (containert &container)
438
+ -> ranget<zip_iteratort<iteratort, decltype(container.begin())>>
439
+ {
440
+ return zip (
441
+ ranget<decltype (container.begin ())>{container.begin (), container.end ()});
442
+ }
443
+
340
444
bool empty () const
341
445
{
342
446
return begin_value == end_value;
0 commit comments