userver: userver/formats/common/items.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
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 {
28 public:
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
93 private:
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