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