userver: userver/utils/meta.hpp Source File
Loading...
Searching...
No Matches
meta.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/meta.hpp
4/// @brief Metaprogramming, template variables and concepts
5/// @ingroup userver_universal
6
7#include <iosfwd>
8#include <iterator>
9#include <optional>
10#include <type_traits>
11#include <vector>
12
13#include <userver/utils/meta_light.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace meta {
18
19namespace impl {
20
21using std::begin;
22using std::end;
23
24template <typename T>
25using KeyType = typename T::key_type;
26
27template <typename T>
28using MappedType = typename T::mapped_type;
29
30template <typename T>
31using IsRange = ExpectSame<std::decay_t<decltype(begin(std::declval<T&>()))>,
32 std::decay_t<decltype(end(std::declval<T&>()))>>;
33
34template <typename T>
35using IteratorType = std::enable_if_t<kIsDetected<IsRange, T>,
36 decltype(begin(std::declval<T&>()))>;
37
38template <typename T, typename = void>
39struct IsIterator : std::false_type {};
40
41template <typename T>
42struct IsIterator<
43 T, std::void_t<typename std::iterator_traits<T>::iterator_category>>
44 : std::true_type {};
45
46template <typename T>
47using RangeValueType =
48 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
49
50template <typename T>
51using OstreamWriteResult =
52 decltype(std::declval<std::ostream&>()
53 << std::declval<const std::remove_reference_t<T>&>());
54
55template <typename T, typename U>
56using EqualityComparisonResult =
57 decltype(std::declval<const T&>() == std::declval<const U&>());
58
59template <typename T>
60using StdHashResult = decltype(std::hash<T>{}(std::declval<const T&>()));
61
62template <typename T>
63using IsSizable = decltype(std::size(std::declval<T>()));
64
65template <typename T>
66using ReserveResult = decltype(std::declval<T&>().reserve(1));
67
68template <typename T>
69using AtResult =
70 decltype(std::declval<const T&>().at(std::declval<typename T::key_type>()));
71
72template <typename T>
73using SubscriptOperatorResult =
74 decltype(std::declval<T>()[std::declval<typename T::key_type>()]);
75
76template <typename T>
77using PushBackResult = decltype(std::declval<T&>().push_back({}));
78
79template <typename T>
80struct IsFixedSizeContainer : std::false_type {};
81
82// Boost and std arrays
83template <typename T, std::size_t Size,
84 template <typename, std::size_t> typename Array>
85struct IsFixedSizeContainer<Array<T, Size>>
86 : std::bool_constant<sizeof(Array<T, Size>) == sizeof(T) * Size> {};
87
88template <typename... Args>
89constexpr bool IsSingleRange() {
90 if constexpr (sizeof...(Args) == 1) {
91 return kIsDetected<IsRange, Args...>;
92 } else {
93 return false;
94 }
95}
96
97} // namespace impl
98
99template <typename T>
100inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
101
102template <typename T>
103inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
104
105/// Returns true if T is an ordered or unordered map or multimap
106template <typename T>
107inline constexpr bool kIsMap =
108 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
109 kIsDetected<impl::MappedType, T>;
110
111/// Returns true if T is a map (but not a multimap!)
112template <typename T>
113inline constexpr bool kIsUniqueMap =
114 kIsMap<T> && kIsDetected<impl::SubscriptOperatorResult,
115 T>; // no operator[] in multimaps
116
117template <typename T>
118using MapKeyType = DetectedType<impl::KeyType, T>;
119
120template <typename T>
121using MapValueType = DetectedType<impl::MappedType, T>;
122
123template <typename T>
124using RangeValueType = DetectedType<impl::RangeValueType, T>;
125
126template <typename T>
127inline constexpr bool kIsRecursiveRange =
128 std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
129
130template <typename T>
131inline constexpr bool kIsIterator = impl::IsIterator<T>::value;
132
133template <typename T>
134inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
135
136template <typename T>
137inline constexpr bool kIsOstreamWritable =
138 std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
139
140template <typename T, typename U = T>
141inline constexpr bool kIsEqualityComparable =
142 std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>, bool>;
143
144template <typename T>
145inline constexpr bool kIsStdHashable =
146 std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> &&
147 kIsEqualityComparable<T>;
148
149/// @brief Check if std::size is applicable to container
150template <typename T>
151inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
152
153/// @brief Check if a container has `reserve`
154template <typename T>
155inline constexpr bool kIsReservable = kIsDetected<impl::ReserveResult, T>;
156
157/// @brief Check if a container has 'push_back'
158template <typename T>
159inline constexpr bool kIsPushBackable = kIsDetected<impl::PushBackResult, T>;
160
161/// @brief Check if a container has fixed size (e.g. std::array)
162template <typename T>
163inline constexpr bool kIsFixedSizeContainer =
165
166/// @brief Returns default inserter for a container
167template <typename T>
168auto Inserter(T& container) {
169 if constexpr (kIsPushBackable<T>) {
170 return std::back_inserter(container);
171 } else if constexpr (kIsFixedSizeContainer<T>) {
172 return container.begin();
173 } else {
174 return std::inserter(container, container.end());
175 }
176}
177
178} // namespace meta
179
180USERVER_NAMESPACE_END