Skip to content

Commit

Permalink
enumerate: compatible to std::iterator_traits
Browse files Browse the repository at this point in the history
  • Loading branch information
felixguendling committed Sep 18, 2024
1 parent f08f454 commit d5279b4
Showing 1 changed file with 69 additions and 21 deletions.
90 changes: 69 additions & 21 deletions include/utl/enumerate.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,88 @@
// source: http://reedbeta.com/blog/python-like-enumerate-in-cpp17/

#include <cstddef>
#include <iterator>
#include <tuple>

#include "utl/forward_type.h"

namespace utl {

template <typename TIter>
struct enumerate_iterator {
using difference_type = std::ptrdiff_t;
using value_type =
std::tuple<std::size_t, typename std::iterator_traits<TIter>::value_type>;
using iterator_category = std::iterator_traits<TIter>::iterator_category;
using reference = value_type;
using pointer = std::add_pointer_t<value_type>;

difference_type operator-(enumerate_iterator const& o) {
return static_cast<std::ptrdiff_t>(i_) - static_cast<std::ptrdiff_t>(o.i_);
}

bool operator!=(enumerate_iterator const& o) const {
return iter_ != o.iter_;
}

void operator++() {
++i_;
++iter_;
}

void operator--()
requires(std::bidirectional_iterator<TIter>)
{
++i_;
++iter_;
}

void operator+=(difference_type const n)
requires(std::random_access_iterator<TIter>)
{
i_ += static_cast<std::size_t>(n);
iter_ += static_cast<std::iterator_traits<TIter>::difference_type>(n);
}

void operator-=(difference_type const n)
requires(std::random_access_iterator<TIter>)
{
i_ = static_cast<std::size_t>(static_cast<difference_type>(i_) - n);
iter_ -= static_cast<std::iterator_traits<TIter>::difference_type>(n);
}

auto operator*() const {
using Type = std::decay_t<decltype(*iter_)>;
if constexpr (std::is_pointer_v<std::decay_t<Type>>) {
return std::make_tuple(i_, &(**iter_));
} else {
return std::tuple<std::size_t, forward_type_t<decltype(*iter_)>>{i_,
*iter_};
}
}

std::size_t i_;
TIter iter_;
};

static_assert(std::is_same_v<
std::ptrdiff_t,
std::iterator_traits<enumerate_iterator<int*>>::difference_type>);

template <typename T, typename TIter = decltype(std::begin(std::declval<T>())),
typename = decltype(std::end(std::declval<T>()))>
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<decltype(*iter_)>;
if constexpr (std::is_pointer_v<std::decay_t<Type>>) {
return std::make_tuple(i_, &(**iter_));
} else {
return std::tuple<std::size_t, forward_type_t<decltype(*iter_)>>{
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_;
};

Expand Down

0 comments on commit d5279b4

Please sign in to comment.