diff --git a/include/utl/enumerate.h b/include/utl/enumerate.h index 0cb554b..5548dab 100644 --- a/include/utl/enumerate.h +++ b/include/utl/enumerate.h @@ -3,40 +3,88 @@ // source: http://reedbeta.com/blog/python-like-enumerate-in-cpp17/ #include +#include #include #include "utl/forward_type.h" namespace utl { +template +struct enumerate_iterator { + using difference_type = std::ptrdiff_t; + using value_type = + std::tuple::value_type>; + using iterator_category = std::iterator_traits::iterator_category; + using reference = value_type; + using pointer = std::add_pointer_t; + + difference_type operator-(enumerate_iterator const& o) { + return static_cast(i_) - static_cast(o.i_); + } + + bool operator!=(enumerate_iterator const& o) const { + return iter_ != o.iter_; + } + + void operator++() { + ++i_; + ++iter_; + } + + void operator--() + requires(std::bidirectional_iterator) + { + ++i_; + ++iter_; + } + + void operator+=(difference_type const n) + requires(std::random_access_iterator) + { + i_ += static_cast(n); + iter_ += static_cast::difference_type>(n); + } + + void operator-=(difference_type const n) + requires(std::random_access_iterator) + { + i_ = static_cast(static_cast(i_) - n); + iter_ -= static_cast::difference_type>(n); + } + + auto operator*() const { + using Type = std::decay_t; + if constexpr (std::is_pointer_v>) { + return std::make_tuple(i_, &(**iter_)); + } else { + return std::tuple>{i_, + *iter_}; + } + } + + std::size_t i_; + TIter iter_; +}; + +static_assert(std::is_same_v< + std::ptrdiff_t, + std::iterator_traits>::difference_type>); + template ())), typename = decltype(std::end(std::declval()))> constexpr auto enumerate(T&& iterable) { - struct iterator { - bool operator!=(iterator const& o) const { return iter_ != o.iter_; } - - void operator++() { - ++i_; - ++iter_; + struct iterable_wrapper { + auto begin() { + using std::begin; + return enumerate_iterator{0U, begin(iterable_)}; } - auto operator*() const { - using Type = std::decay_t; - if constexpr (std::is_pointer_v>) { - return std::make_tuple(i_, &(**iter_)); - } else { - return std::tuple>{ - i_, *iter_}; - } + auto end() { + using std::end; + return enumerate_iterator{0U, end(iterable_)}; } - std::size_t i_; - TIter iter_; - }; - - struct iterable_wrapper { - auto begin() { return iterator{0U, std::begin(iterable_)}; } - auto end() { return iterator{0U, std::end(iterable_)}; } T iterable_; };