#ifndef ITER_ZIP_LONGEST_HPP_ #define ITER_ZIP_LONGEST_HPP_ #include "internal/iterbase.hpp" #include #include #include #include namespace iter { namespace impl { template class ZippedLongest; template ZippedLongest zip_longest_impl( TupleType&&, std::index_sequence); } template auto zip_longest(Containers&&... containers); } template class iter::impl::ZippedLongest { private: TupleType containers; friend ZippedLongest zip_longest_impl( TupleType&&, std::index_sequence); template using OptType = boost::optional>>; using ZipIterDeref = std::tuple...>; ZippedLongest(TupleType&& in_containers) : containers(std::move(in_containers)) {} public: ZippedLongest(ZippedLongest&&) = default; class Iterator : public std::iterator { private: iterator_tuple_type iters; iterator_tuple_type ends; public: Iterator(iterator_tuple_type&& in_iters, iterator_tuple_type&& in_ends) : iters(std::move(in_iters)), ends(std::move(in_ends)) {} Iterator& operator++() { // increment every iterator that's not already at // the end absorb(((std::get(this->iters) != std::get(this->ends)) ? (++std::get(this->iters), 0) : 0)...); return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } bool operator!=(const Iterator& other) const { if (sizeof...(Is) == 0) return false; bool results[] = { false, (std::get(this->iters) != std::get(other.iters))...}; return std::any_of( std::begin(results), std::end(results), [](bool b) { return b; }); } bool operator==(const Iterator& other) const { return !(*this != other); } ZipIterDeref operator*() { return ZipIterDeref{ ((std::get(this->iters) != std::get(this->ends)) ? OptType{*std::get(this->iters)} : OptType{})...}; } auto operator -> () -> ArrowProxy { return {**this}; } }; Iterator begin() { return {iterator_tuple_type{ std::begin(std::get(this->containers))...}, iterator_tuple_type{ std::end(std::get(this->containers))...}}; } Iterator end() { return {iterator_tuple_type{ std::end(std::get(this->containers))...}, iterator_tuple_type{ std::end(std::get(this->containers))...}}; } }; template iter::impl::ZippedLongest iter::impl::zip_longest_impl( TupleType&& in_containers, std::index_sequence) { return {std::move(in_containers)}; } template auto iter::zip_longest(Containers&&... containers) { return impl::zip_longest_impl( std::tuple{std::forward(containers)...}, std::index_sequence_for{}); } #endif