#ifndef ITERATOR_ITERATOR_HPP_ #define ITERATOR_ITERATOR_HPP_ #include "iterbase.hpp" #include "zip.hpp" #include #include #include // IterIterWrapper and IteratorIterator provide a means to have a container // of iterators act like a container of the pointed to objects. This is useful // for combinatorics and similar itertools which need to keep track of // more than one element at a time. // an IterIterWrapper::iterator>> // behave like some_collection when iterated over or indexed namespace iter { template struct HasConstDeref : std::false_type { }; template struct HasConstDeref())>> : std::true_type { }; template ::difference_type> class IteratorIterator : public std::iterator< std::random_access_iterator_tag, typename std::iterator_traits::value_type, Diff, typename std::iterator_traits::pointer, typename std::iterator_traits::reference > { static_assert(std::is_same< typename std::iterator_traits::iterator_category, std::random_access_iterator_tag>::value, "IteratorIterator only works with random access iterators"); private: Iter sub_iter; public: IteratorIterator() = default; IteratorIterator(const Iter& it) : sub_iter{it} { } bool operator==(const IteratorIterator& other) const { return !(*this != other); } bool operator!=(const IteratorIterator& other) const { return this->sub_iter != other.sub_iter; } IteratorIterator& operator++() { ++this->sub_iter; return *this; } IteratorIterator operator++(int) { auto ret = *this; ++*this; return ret; } IteratorIterator& operator--() { --this->sub_iter; return *this; } IteratorIterator operator--(int) { auto ret = *this; --*this; return ret; } decltype(auto) operator*() { return **this->sub_iter; } decltype(auto) operator->() { return *this->sub_iter; } IteratorIterator& operator+=(Diff n) { this->sub_iter += n; return *this; } IteratorIterator operator+(Diff n) const { auto it = *this; it += n; return it; } friend IteratorIterator operator+(Diff n, IteratorIterator it) { it += n; return it; } IteratorIterator& operator-=(Diff n) { this->sub_iter -= n; return *this; } IteratorIterator operator-(Diff n) const { auto it = *this; it -= n; return it; } friend IteratorIterator operator-(Diff n, IteratorIterator it) { it -= n; return it; } Diff operator-(const IteratorIterator& rhs) const { return this->sub_iter - rhs.sub_iter; } decltype(auto) operator[](Diff idx) { return *sub_iter[idx]; } bool operator<(const IteratorIterator& rhs) const { return this->sub_iter < rhs.sub_iter; } bool operator>(const IteratorIterator& rhs) const { return this->sub_iter > rhs.sub_iter; } bool operator<=(const IteratorIterator& rhs) const { return this->sub_iter <= rhs.sub_iter; } bool operator>=(const IteratorIterator& rhs) const { return this->sub_iter >= rhs.sub_iter; } }; template class IterIterWrapper { private: Container container; using contained_iter = typename Container::value_type; using size_type = typename Container::size_type; using iterator = IteratorIterator; using const_iterator = IteratorIterator; using reverse_iterator = IteratorIterator; using const_reverse_iterator = IteratorIterator; template struct ConstAtTypeOrVoid : type_is { }; template struct ConstAtTypeOrVoid < U, void_t().at(0))>> : type_is().at(0))> { }; using const_at_type_or_void_t = typename ConstAtTypeOrVoid<>::type; template struct ConstIndexTypeOrVoid : type_is { }; template struct ConstIndexTypeOrVoid < U, void_t()[0])>> : type_is()[0])> { }; using const_index_type_or_void_t = typename ConstIndexTypeOrVoid<>::type; public: IterIterWrapper() = default; explicit IterIterWrapper(size_type sz) : container(sz) { } IterIterWrapper(size_type sz, const contained_iter& val) : container(sz, val) { } decltype(auto) at(size_type pos) { return *container.at(pos); } decltype(auto) at(size_type pos) const { return *container.at(pos); } decltype(auto) operator[](size_type pos) noexcept(noexcept(*container[pos])) { return *container[pos]; } decltype(auto) operator[](size_type pos) const noexcept(noexcept(*container[pos])) { return *container[pos]; } bool empty() const noexcept { return container.empty(); } size_type size() const noexcept { return container.size(); } iterator begin() noexcept { return {container.begin()}; } iterator end() noexcept { return {container.end()}; } const_iterator begin() const noexcept { return {container.begin()}; } const_iterator end() const noexcept { return {container.end()}; } const_iterator cbegin() const noexcept { return {container.cbegin()}; } const_iterator cend() const noexcept { return {container.cend()}; } reverse_iterator rbegin() noexcept { return {container.rbegin()}; } reverse_iterator rend() noexcept { return {container.rend()}; } const_reverse_iterator rbegin() const noexcept { return {container.rbegin()}; } const_reverse_iterator rend() const noexcept { return {container.rend()}; } const_reverse_iterator crbegin() const noexcept { return {container.rbegin()}; } const_reverse_iterator crend() const noexcept { return {container.rend()}; } // get() exposes the underlying container. this allows the // itertools to manipulate the iterators in the container // and should not be depended on anywhere else. Container& get() noexcept { return container; } const Container& get() const noexcept { return container; } }; } #endif