/* ***************************************************************************** * Copyright (c) 2020 Krystian Stasiowski * * This code adapted from code written by Krystian Stasiowski * * * No specific license provisions were given, however permission was granted for * me to include it in kblib. * * His code is much faster and cleaner than my magic_enumerate is. HOWEVER, it * is fundamentally unable to detect the copying-nonconst-from-const case. * * My modifications are: * - Change from [val, idx] to [idx, val] to match Python's enumerate() * - Wrote documentation * - Change name from value_and_index() to cry_enumerate() * - Silenced Clang warnings about std::tuple_element specializations with * mismatched tags. * - Formatting * * All credit for everything else goes to Krystian. * * ****************************************************************************/ #ifndef ENUMERATECONTRIB_H #define ENUMERATECONTRIB_H #include "tdecl.h" #include #include #if KBLIB_USE_CXX17 namespace KBLIB_NS { /** * @internal */ namespace detail_cry { template struct value_index_pair; template * = nullptr> auto get(T&& t) -> std::conditional_t, const std::size_t&, const std::size_t> { return t.index; } template * = nullptr> auto get(T&& t) -> std::conditional_t, typename std::remove_reference_t::value_type&, typename std::remove_reference_t::value_type> { // static_assert(std::is_reference_v); // static_assert( // std::is_const_v>); return *t.iter; } template struct value_index_pair { using value_type = std::remove_reference_t())>; std::size_t index; Iterator iter; }; template struct value_and_index_base { public: using iterator_type = decltype(std::begin(std::declval())); value_and_index_base(Range& range) : range_begin_(std::begin(range)) , range_end_(std::end(range)) {} auto range_begin() -> iterator_type { return range_begin_; } auto range_end() -> iterator_type { return range_end_; } iterator_type range_begin_; iterator_type range_end_; }; template struct value_and_index_base< Range, std::enable_if_t>> { public: using iterator_type = decltype(std::begin(std::declval())); value_and_index_base(Range& range) : range_(std::move(range)) {} auto range_begin() -> iterator_type { return std::begin(range_); } auto range_end() -> iterator_type { return std::end(range_); } Range range_; }; template struct value_and_index_impl : value_and_index_base { using iterator_type = typename value_and_index_base::iterator_type; value_and_index_impl(Range& range) : value_and_index_base(range) , begin_(this->range_begin(), 0) , end_(this->range_end(), 0) {} struct iterator { private: value_index_pair pair_; public: iterator(iterator_type iter, std::size_t index = 0) : pair_{index, iter} {} auto operator*() -> value_index_pair& { return pair_; } auto operator++(int) -> iterator { iterator copy(pair_.iter, pair_.index); ++pair_.iter, ++pair_.index; return copy; } auto operator++() -> iterator& { ++pair_.iter, ++pair_.index; return *this; } auto operator==(const iterator& other) const -> bool { return other.pair_.iter == pair_.iter; } auto operator!=(const iterator& other) const -> bool { return not (other == *this); } }; auto begin() -> iterator { return begin_; } auto end() -> iterator { return end_; } private: iterator begin_; iterator end_; }; } // namespace detail_cry } // namespace KBLIB_NS namespace std { # if defined(__clang__) // Fix from: https://github.com/nlohmann/json/issues/1401 # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wmismatched-tags" # endif template struct tuple_size> { static constexpr std::size_t value = 2; }; template struct tuple_element<0, kblib::detail_cry::value_index_pair> { using type = const std::size_t; }; template struct tuple_element<1, kblib::detail_cry::value_index_pair> { using type = std::remove_reference_t())>; }; # if defined(__clang__) # pragma clang diagnostic pop # endif } // namespace std namespace KBLIB_NS { /** * @brief * * @author Krystian Stasiowski, killerbee * @date 2020 */ template auto cry_enumerate(Range&& range) -> auto { return detail_cry::value_and_index_impl(range); } } // namespace KBLIB_NS #endif #endif // ENUMERATECONTRIB_H