userver: userver/utils/enumerate.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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