@@ -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,26 @@ 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+
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+
340444 bool empty () const
341445 {
342446 return begin_value == end_value;
0 commit comments