#ifndef ITER_ZIP_HPP_ #define ITER_ZIP_HPP_ #include "internal/iter_tuples.hpp" #include "internal/iterbase.hpp" #include #include #include #include namespace iter { namespace impl { template class Zipped; template Zipped zip_impl(TupleType&&, std::index_sequence); } template auto zip(Containers&&... containers); } template class iter::impl::Zipped { private: TupleType containers_; friend Zipped iter::impl::zip_impl( TupleType&&, std::index_sequence); Zipped(TupleType&& containers) : containers_(std::move(containers)) {} public: Zipped(Zipped&&) = default; // template templates here because I need to defer evaluation in the const // iteration case for types that don't have non-const begin() and end(). If I // passed in the actual types of the tuples of iterators and the type for // deref they'd need to be known in the function declarations below. template class IteratorTuple, template class TupleDeref> class Iterator { // see gcc bug 87651 #if NO_GCC_FRIEND_ERROR private: template class, template class> friend class Iterator; #else public: #endif IteratorTuple iters_; public: using iterator_category = std::input_iterator_tag; using value_type = TupleDeref; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; Iterator(IteratorTuple&& iters) : iters_(std::move(iters)) {} Iterator& operator++() { absorb(++std::get(iters_)...); return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } template class IT, template class TD> bool operator!=(const Iterator& other) const { if constexpr (sizeof...(Is) == 0) { return false; } else { return (... && (std::get(iters_) != std::get(other.iters_))); } } template class IT, template class TD> bool operator==(const Iterator& other) const { return !(*this != other); } TupleDeref operator*() { return {(*std::get(iters_))...}; } auto operator-> () -> ArrowProxy { return {**this}; } }; Iterator begin() { return {{get_begin(std::get(containers_))...}}; } Iterator end() { return {{get_end(std::get(containers_))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> begin() const { return {{get_begin(std::as_const(std::get(containers_)))...}}; } Iterator, const_iterator_tuple_type, const_iterator_deref_tuple> end() const { return {{get_end(std::as_const(std::get(containers_)))...}}; } }; template iter::impl::Zipped iter::impl::zip_impl( TupleType&& containers, std::index_sequence) { return {std::move(containers)}; } template auto iter::zip(Containers&&... containers) { return impl::zip_impl( std::tuple{std::forward(containers)...}, std::index_sequence_for{}); } #endif