#ifndef ITER_ENUMERATE_H_ #define ITER_ENUMERATE_H_ #include "internal/iterbase.hpp" #include #include #include #include #include namespace iter { namespace impl { template class Enumerable; } template impl::Enumerable enumerate(Container&&, std::size_t = 0); template impl::Enumerable> enumerate( std::initializer_list, std::size_t = 0); } template class iter::impl::Enumerable { private: Container container; const std::size_t start; // The only thing allowed to directly instantiate an Enumerable is // the enumerate function friend Enumerable iter::enumerate(Container&&, std::size_t); template friend Enumerable> iter::enumerate( std::initializer_list, std::size_t); // for IterYield using BasePair = std::pair>; // Value constructor for use only in the enumerate function Enumerable(Container&& in_container, std::size_t in_start) : container(std::forward(in_container)), start{in_start} {} public: Enumerable(Enumerable&&) = default; // "yielded" by the Enumerable::Iterator. Has a .index, and a // .element referencing the value yielded by the subiterator class IterYield : public BasePair { public: using BasePair::BasePair; typename BasePair::first_type& index = BasePair::first; typename BasePair::second_type& element = BasePair::second; }; // Holds an iterator of the contained type and a size_t for the // index. Each call to ++ increments both of these data members. // Each dereference returns an IterYield. class Iterator : public std::iterator { private: iterator_type sub_iter; std::size_t index; public: Iterator(iterator_type&& si, std::size_t start) : sub_iter{std::move(si)}, index{start} {} IterYield operator*() { return {this->index, *this->sub_iter}; } ArrowProxy operator->() { return {**this}; } Iterator& operator++() { ++this->sub_iter; ++this->index; return *this; } Iterator operator++(int) { auto ret = *this; ++*this; return ret; } bool operator!=(const Iterator& other) const { return this->sub_iter != other.sub_iter; } bool operator==(const Iterator& other) const { return !(*this != other); } }; Iterator begin() { return {std::begin(this->container), start}; } Iterator end() { return {std::end(this->container), start}; } }; template iter::impl::Enumerable iter::enumerate( Container&& container, std::size_t start) { return {std::forward(container), start}; } template iter::impl::Enumerable> iter::enumerate( std::initializer_list il, std::size_t start) { return {std::move(il), start}; } #endif