#pragma once /* * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BLT_ITERATOR_ENUMERATE_H #define BLT_ITERATOR_ENUMERATE_H #include #include namespace blt { namespace iterator { /** * struct which is returned by the enumerator. * @tparam T type to store. */ template struct enumerate_item { blt::size_t index; T value; }; template class enumerate_wrapper : public passthrough_wrapper> { public: enumerate_wrapper(blt::size_t index, Iter iter): passthrough_wrapper>(std::move(iter)), index(index) {} using iterator_category = typename std::iterator_traits::iterator_category; using value_type = enumerate_item>; using difference_type = blt::ptrdiff_t; using pointer = value_type; using reference = value_type; enumerate_item> operator*() const { return {index, *this->iter}; } enumerate_wrapper& operator++() { ++index; ++this->iter; return *this; } enumerate_wrapper& operator--() { --index; --this->iter; return *this; } friend enumerate_wrapper operator+(const enumerate_wrapper& a, blt::ptrdiff_t n) { static_assert(meta::is_random_access_iterator_v, "Iterator must allow random access"); auto copy = a; copy.index += n; copy.iter = copy.iter + n; return copy; } friend enumerate_wrapper operator-(const enumerate_wrapper& a, blt::ptrdiff_t n) { static_assert(meta::is_random_access_iterator_v, "Iterator must allow random access"); auto copy = a; copy.index -= n; copy.iter = copy.iter - n; return copy; } private: blt::size_t index; }; } template class enumerate_iterator_container : public iterator::iterator_container> { public: using iterator::iterator_container>::iterator_container; enumerate_iterator_container(Iter begin, Iter end, blt::size_t size): iterator::iterator_container>( iterator::enumerate_wrapper{0, std::move(begin)}, iterator::enumerate_wrapper{size, std::move(end)}) {} }; template enumerate_iterator_container(Iter, Iter, blt::size_t) -> enumerate_iterator_container; namespace iterator::impl { template class enumerate_t { public: auto enumerate() { auto* d = static_cast(this); return enumerate_iterator_container{d->begin(), d->end(), static_cast(std::distance(d->begin(), d->end()))}; } }; } template static inline auto enumerate(T& container) { return enumerate_iterator_container{container.begin(), container.end(), container.size()}; } template static inline auto enumerate(const T& container) { return enumerate_iterator_container{container.begin(), container.end(), container.size()}; } template static inline auto enumerate(const T(& container)[size]) { return enumerate_iterator_container{&container[0], &container[size], size}; } template static inline auto enumerate(T(& container)[size]) { return enumerate_iterator_container{&container[0], &container[size], size}; } } #endif //BLT_ITERATOR_ENUMERATE_H