Skip to content

Commit b199026

Browse files
Add zip method on ranget
Allow to construct a range of pairs from a pair of ranges
1 parent e2fbcde commit b199026

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

src/util/range.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,90 @@ struct concat_iteratort
265265
second_iteratort second_begin;
266266
};
267267

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+
268352
/// A range is a pair of a begin and an end iterators.
269353
/// The class provides useful methods such as map, filter and concat which only
270354
/// manipulate iterators and thus don't have to create instances of heavy data
@@ -337,6 +421,18 @@ struct ranget final
337421
concat_begin, concat_end);
338422
}
339423

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+
340436
bool empty() const
341437
{
342438
return begin_value == end_value;

0 commit comments

Comments
 (0)