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()
19 -> std::pair<const std::size_t, decltype(*std::declval<Iter>())>;
20
21template <typename Iter, typename... Args>
22auto DetectEnumerateValueType(Args&&...) -> void;
23
24template <typename Iter>
25struct IteratorWrapper {
26 using difference_type = std::ptrdiff_t;
27 using value_type = decltype(DetectEnumerateValueType<Iter>());
28 using reference = value_type;
29 using iterator_category = std::input_iterator_tag;
30
31 Iter iterator;
32 std::size_t pos{0};
33
34 constexpr IteratorWrapper& operator++() {
35 ++pos;
36 ++iterator;
37 return *this;
38 }
39
40 constexpr value_type operator*() const { return {pos, *iterator}; }
41
42 template <typename OtherIter>
43 constexpr bool operator==(const IteratorWrapper<OtherIter>& other) const {
44 return iterator == other.iterator;
45 }
46
47 template <typename OtherIter>
48 constexpr bool operator!=(const IteratorWrapper<OtherIter>& other) const {
49 return !(iterator == other.iterator);
50 }
51};
52
53template <typename Range>
54using IteratorTypeOf = decltype(std::begin(std::declval<Range&>()));
55
56template <typename Range>
57using SentinelTypeOf = decltype(std::end(std::declval<Range&>()));
58
59template <typename Container>
60struct ContainerWrapper {
61 constexpr IteratorWrapper<IteratorTypeOf<Container>> begin() {
62 return {std::begin(container), 0};
63 }
64
65 constexpr IteratorWrapper<SentinelTypeOf<Container>> end() {
66 return {std::end(container), 0};
67 }
68
69 constexpr IteratorWrapper<IteratorTypeOf<const Container>> begin() const {
70 return {std::begin(container), 0};
71 }
72
73 constexpr IteratorWrapper<SentinelTypeOf<const Container>> end() const {
74 return {std::end(container), 0};
75 }
76
77 Container container;
78};
79
80} // namespace utils::impl
81
82namespace utils {
83
84/// @brief Implementation of python-style enumerate function for range-for loops
85/// @param iterable: Container to iterate
86/// @returns ContainerWrapper, which iterator after dereference returns pair
87/// of index and (!!!)non-const reference to element(it seems impossible to make
88/// this reference const). It can be used in "range based for loop" with
89/// "structured binding" like this
90/// @code
91/// for (auto [pos, elem] : enumerate(someContainer)) {...}
92/// @endcode
93template <typename Container>
94constexpr auto enumerate(Container&& iterable) {
95 return impl::ContainerWrapper<Container>{std::forward<Container>(iterable)};
96}
97
98} // namespace utils
99
100USERVER_NAMESPACE_END