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 value_type operator*() const { return {pos, *iterator}; }
40
41 template <typename OtherIter>
42 constexpr bool operator==(const IteratorWrapper<OtherIter>& other) const {
43 return iterator == other.iterator;
44 }
45
46 template <typename OtherIter>
47 constexpr bool operator!=(const IteratorWrapper<OtherIter>& other) const {
48 return !(iterator == other.iterator);
49 }
50};
51
52template <typename Range>
53using IteratorTypeOf = decltype(std::begin(std::declval<Range&>()));
54
55template <typename Range>
56using SentinelTypeOf = decltype(std::end(std::declval<Range&>()));
57
58template <typename Container>
59struct ContainerWrapper {
60 constexpr IteratorWrapper<IteratorTypeOf<Container>> begin() { return {std::begin(container), 0}; }
61
62 constexpr IteratorWrapper<SentinelTypeOf<Container>> end() { return {std::end(container), 0}; }
63
64 constexpr IteratorWrapper<IteratorTypeOf<const Container>> begin() const { return {std::begin(container), 0}; }
65
66 constexpr IteratorWrapper<SentinelTypeOf<const Container>> end() const { return {std::end(container), 0}; }
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 (!!!)non-const reference to element(it seems impossible to make
79/// this reference const). It can be used in "range based for loop" with
80/// "structured binding" like this
81/// @code
82/// for (auto [pos, elem] : enumerate(someContainer)) {...}
83/// @endcode
84template <typename Container>
85constexpr auto enumerate(Container&& iterable) {
86 return impl::ContainerWrapper<Container>{std::forward<Container>(iterable)};
87}
88
89} // namespace utils
90
91USERVER_NAMESPACE_END