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)
45 : it_(std::move(it))
46 {}
47 /// @endcond
48
49 Iterator(const Iterator& other) = default;
50 Iterator(Iterator&& other) noexcept = default;
51
52 Iterator& operator=(const Iterator& other) = default;
53 Iterator& operator=(Iterator&& other) noexcept = default;
54
55 reference operator*() const { return {it_.GetName(), *it_}; }
56
57 Iterator operator++(int) {
58 auto it = *this;
59 ++*this;
60 return it;
61 }
62
63 Iterator& operator++() {
64 ++it_;
65 return *this;
66 }
67
68 bool operator==(const Iterator& other) const { return it_ == other.it_; }
69
70 bool operator!=(const Iterator& other) const { return !(*this == other); }
71
72 private:
73 RawIterator it_;
74 };
75
76 /// @brief Satisfies `std::forward_iterator`, `std::common_iterator`,
77 /// with `std::iter_reference_t` equal to
78 /// formats::common::ItemsWrapperValue<Value>.
79 using iterator = Iterator<false>;
80
81 /// @brief Satisfies `std::forward_iterator`, `std::common_iterator`,
82 /// with `std::iter_reference_t` equal to
83 /// formats::common::ItemsWrapperValue<const Value>.
84 using const_iterator = Iterator<true>;
85
86 /// @cond
87 explicit ItemsWrapper(Value&& value)
88 : value_(static_cast<Value&&>(value))
89 {}
90 /// @endcond
91
92 iterator begin() { return iterator(value_.begin()); }
93 iterator end() { return iterator(value_.end()); }
94 const_iterator begin() const { return const_iterator(value_.begin()); }
95 const_iterator end() const { return const_iterator(value_.end()); }
96
97private:
98 Value value_;
99};
100
101/// @brief Wrapper for handy python-like iteration over a map
102///
103/// @code
104/// for (const auto& [name, value]: Items(map)) ...
105/// @endcode
106///
107/// To move out values:
108/// @code
109/// for (auto [name, value]: Items(map)) {
110/// vector.push_back(std::move(name));
111/// // value is a const reference and can not be moved
112/// }
113/// @endcode
114///
115/// ## Example usage:
116///
117/// @snippet universal/src/formats/common/items_test.cpp Items Example Usage - Simple object
118template <typename Value>
119ItemsWrapper<Value> Items(Value&& value) {
120 // when passed an lvalue, store by reference
121 // when passed an rvalue, store by value
122 return ItemsWrapper<Value>(static_cast<Value&&>(value));
123}
124
125} // namespace formats::common
126
127USERVER_NAMESPACE_END