userver: userver/utils/enumerate.hpp Source File
Loading...
Searching...
No Matches
enumerate.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/enumerate.hpp
4/// @brief @copybrief utils::enumerate
5/// @ingroup userver_universal
6
7#include <cstddef>
8#include <cstdint>
9#include <iterator>
10#include <type_traits>
11#include <utility>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils::impl {
16
17template <typename Iter>
18auto DetectEnumerateValueType() -> std::pair<const std::size_t, decltype(*std::declval<Iter>())>;
19
20template <typename Iter, typename... Args>
21auto DetectEnumerateValueType(Args&&...) -> void;
22
23template <typename Iter>
24struct IteratorWrapper {
25 using difference_type = std::ptrdiff_t;
26 using value_type = decltype(DetectEnumerateValueType<Iter>());
27 using reference = value_type;
28 using iterator_category = std::input_iterator_tag;
29
30 Iter iterator;
31 std::size_t pos{0};
32
33 constexpr IteratorWrapper& operator++() {
34 ++pos;
35 ++iterator;
36 return *this;
37 }
38
39 constexpr IteratorWrapper operator++(int) {
40 IteratorWrapper copy{*this};
41 ++*this;
42 return copy;
43 }
44
45 constexpr value_type operator*() const { return {pos, *iterator}; }
46
47 template <typename OtherIter>
48 constexpr bool operator==(const IteratorWrapper<OtherIter>& other) const {
49 return iterator == other.iterator;
50 }
51};
52
53template <typename Iter>
54constexpr IteratorWrapper<Iter> MakeIteratorWrapper(Iter iterator) {
55 return IteratorWrapper<Iter>{.iterator = std::move(iterator), .pos = 0};
56}
57
58template <typename Container>
59struct ContainerWrapper {
60 constexpr auto begin() { return MakeIteratorWrapper(std::begin(container)); }
61
62 constexpr auto end() { return MakeIteratorWrapper(std::end(container)); }
63
64 constexpr auto begin() const { return MakeIteratorWrapper(std::begin(std::as_const(container))); }
65
66 constexpr auto end() const { return MakeIteratorWrapper(std::end(std::as_const(container))); }
67
68 Container container;
69};
70
71} // namespace utils::impl
72
73namespace utils {
74
75/// @brief Implementation of python-style enumerate function for range-for loops
76/// @param iterable: Container to iterate
77/// @returns ContainerWrapper, which iterator after dereference returns pair
78/// of index and reference to element. The reference is const-qualified if either
79/// the wrapper itself or the underlying container is const; otherwise, it is non-const.
80/// It can be used in "range based for loop" with "structured binding" like this
81/// @code
82/// for (auto [pos, elem] : enumerate(someContainer)) {...}
83/// @endcode
84template <typename Container>
85constexpr auto enumerate(Container&& iterable) { // NOLINT(readability-identifier-naming)
86 return impl::ContainerWrapper<Container>{std::forward<Container>(iterable)};
87}
88
89} // namespace utils
90
91USERVER_NAMESPACE_END