userver: userver/formats/common/items.hpp Source File
Loading...
Searching...
No Matches
items.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/formats/common/items.hpp
4/// @brief @copybrief formats::common::Items()
5/// @ingroup userver_universal
6
7#include <cstddef>
8#include <iterator>
9#include <string>
10#include <type_traits>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace formats::common {
15
16/// @see formats::common::ItemsWrapper
17template <typename Value>
18struct ItemsWrapperValue final {
19 std::string key;
20 typename decltype(std::declval<Value&>().begin())::reference value;
21};
22
23/// @brief Wrapper for handy python-like iteration over a map.
24///
25/// See formats::common::Items() for usage example
26template <typename Value>
27class ItemsWrapper final {
28public:
29 /// Exposition-only, do not instantiate directly, use `iterator` and
30 /// `const_iterator` aliases instead.
31 template <bool Const>
32 class Iterator final {
33 using Base = std::conditional_t<Const, const Value, Value>;
34 using RawIterator = decltype(std::declval<Base&>().begin());
35
36 public:
37 using iterator_category = std::forward_iterator_tag;
38 using difference_type = std::ptrdiff_t;
39 using value_type = ItemsWrapperValue<Base>;
40 using reference = value_type;
41 using pointer = void;
42
43 /// @cond
44 explicit Iterator(RawIterator it) : it_(std::move(it)) {}
45 /// @endcond
46
47 Iterator(const Iterator& other) = default;
48 Iterator(Iterator&& other) noexcept = default;
49
50 Iterator& operator=(const Iterator& other) = default;
51 Iterator& operator=(Iterator&& other) noexcept = default;
52
53 reference operator*() const { return {it_.GetName(), *it_}; }
54
55 Iterator operator++(int) {
56 auto it = *this;
57 ++*this;
58 return it;
59 }
60
61 Iterator& operator++() {
62 ++it_;
63 return *this;
64 }
65
66 bool operator==(const Iterator& other) const { return it_ == other.it_; }
67
68 bool operator!=(const Iterator& other) const { return !(*this == other); }
69
70 private:
71 RawIterator it_;
72 };
73
74 /// @brief Satisfies `std::forward_iterator`, `std::common_iterator`,
75 /// with `std::iter_reference_t` equal to
76 /// formats::common::ItemsWrapperValue<Value>.
77 using iterator = Iterator<false>;
78
79 /// @brief Satisfies `std::forward_iterator`, `std::common_iterator`,
80 /// with `std::iter_reference_t` equal to
81 /// formats::common::ItemsWrapperValue<const Value>.
82 using const_iterator = Iterator<true>;
83
84 /// @cond
85 explicit ItemsWrapper(Value&& value) : value_(static_cast<Value&&>(value)) {}
86 /// @endcond
87
88 iterator begin() { return iterator(value_.begin()); }
89 iterator end() { return iterator(value_.end()); }
90 const_iterator begin() const { return const_iterator(value_.begin()); }
91 const_iterator end() const { return const_iterator(value_.end()); }
92
93private:
94 Value value_;
95};
96
97/// @brief Wrapper for handy python-like iteration over a map
98///
99/// @code
100/// for (const auto& [name, value]: Items(map)) ...
101/// @endcode
102///
103/// To move out values:
104/// @code
105/// for (auto [name, value]: Items(map)) {
106/// vector.push_back(std::move(name));
107/// // value is a const reference and can not be moved
108/// }
109/// @endcode
110template <typename Value>
111ItemsWrapper<Value> Items(Value&& value) {
112 // when passed an lvalue, store by reference
113 // when passed an rvalue, store by value
114 return ItemsWrapper<Value>(static_cast<Value&&>(value));
115}
116
117} // namespace formats::common
118
119USERVER_NAMESPACE_END