/* * This file is part of the DXX-Rebirth project . * It is copyright by its individual contributors, as recorded in the * project's Git history. See COPYING.txt at the top level for license * terms and a link to the Git history. */ #pragma once #include #include #include "dxxsconf.h" #include "partial_range.h" #include "ephemeral_range.h" #include #include namespace d_enumerate { namespace detail { template struct adjust_iterator_dereference_type : std::false_type { using value_type = std::tuple; }; template struct adjust_iterator_dereference_type> : std::true_type { using value_type = std::tuple; }; } } template class enumerated_iterator { range_iterator_type m_iter; index_type m_idx; using adjust_iterator_dereference_type = d_enumerate::detail::adjust_iterator_dereference_type; public: using iterator_category = std::forward_iterator_tag; using value_type = typename adjust_iterator_dereference_type::value_type; using difference_type = std::ptrdiff_t; using pointer = value_type *; using reference = value_type &; enumerated_iterator(range_iterator_type &&iter, const index_type idx) : m_iter(std::move(iter)), m_idx(idx) { } value_type operator*() const { if constexpr (adjust_iterator_dereference_type::value) return std::tuple_cat(std::tuple(m_idx), *m_iter); else return {m_idx, *m_iter}; } enumerated_iterator &operator++() { ++ m_iter; ++ m_idx; return *this; } bool operator!=(const enumerated_iterator &i) const { return m_iter != i.m_iter; } bool operator==(const enumerated_iterator &i) const { return m_iter == i.m_iter; } }; template class enumerate : partial_range_t { using base_type = partial_range_t; using iterator_dereference_type = decltype(*std::declval()); using enumerated_iterator_type = enumerated_iterator< index_type, range_iterator_type, typename std::remove_cv::type>; const index_type m_idx; public: using range_owns_iterated_storage = std::false_type; enumerate(const range_iterator_type b, const range_iterator_type e, const index_type i) : base_type(b, e), m_idx(i) { } template enumerate(range_type &&t, const index_type i = index_type{}) : base_type(std::forward(t)), m_idx(i) { static_assert(!any_ephemeral_range::value, "cannot enumerate storage of ephemeral ranges"); static_assert(std::is_rvalue_reference::value || std::is_lvalue_reference::value, "lvalue range must produce lvalue reference enumerated_value"); } enumerated_iterator_type begin() const { return {this->base_type::begin(), m_idx}; } enumerated_iterator_type end() const { return {this->base_type::end(), index_type{} /* unused */}; } }; template ()))> enumerate(range_type &&r, const index_type start = index_type(/* value ignored */)) -> enumerate;