#pragma once #if __cplusplus >= 202302L #include #if __cpp_lib_ranges_enumerate >= 202302L #define JVALIDATE_USE_STD_RANGES_ENUMERATE #endif #endif #ifdef JVALIDATE_USE_STD_RANGES_ENUMERATE namespace jvalidate::detail { using std::ranges::views::enumerate; } #else #include #include #include namespace jvalidate::detail { /** * @brief A replacement for std::ranges::views::enumerate in C++20 (as enumerate * is a C++23 feature). * Much like python's enumerate() function, this is an iterator adapter that * attaches the "index" of the iteration to each element - incrementing it as * we go. */ template class enumurate_iterator { public: using traits_t = std::iterator_traits; using value_type = std::pair; using reference = std::pair; using pointer = DerefProxy; using difference_type = typename traits_t::difference_type; using iterator_category = std::forward_iterator_tag; private: size_t index_ = 0; It iter_; public: enumurate_iterator(It iter) : iter_(iter) {} reference operator*() const { return {index_, *iter_}; } pointer operator->() const { return operator*(); } enumurate_iterator & operator++() { ++index_; ++iter_; return *this; } friend bool operator==(enumurate_iterator rhs, enumurate_iterator lhs) { return rhs.iter_ == lhs.iter_; } friend bool operator!=(enumurate_iterator rhs, enumurate_iterator lhs) { return rhs.iter_ != lhs.iter_; } }; template auto enumerate(C && container) { struct { auto begin() const { return enumurate_iterator(c.begin()); } auto end() const { return enumurate_iterator(c.end()); } C c; } rval{std::forward(container)}; return rval; } } #endif