Github   Telegram
Loading...
Searching...
No Matches
meta.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <iosfwd>
7#include <iterator>
8#include <optional>
9#include <type_traits>
10#include <vector>
11
13
14USERVER_NAMESPACE_BEGIN
15
16namespace meta {
17
28struct NotDetected {};
29
30namespace impl {
31
32template <typename Default, typename AlwaysVoid,
33 template <typename...> typename Trait, typename... Args>
34struct Detector {
35 using type = Default;
36};
37
38template <typename Default, template <typename...> typename Trait,
39 typename... Args>
40struct Detector<Default, utils::void_t<Trait<Args...>>, Trait, Args...> {
41 using type = Trait<Args...>;
42};
43
44} // namespace impl
45
47template <template <typename...> typename Trait, typename... Args>
48inline constexpr bool kIsDetected = !std::is_same_v<
49 typename impl::Detector<NotDetected, void, Trait, Args...>::type,
51
54template <template <typename...> typename Trait, typename... Args>
56 typename impl::Detector<NotDetected, void, Trait, Args...>::type;
57
60template <typename Default, template <typename...> typename Trait,
61 typename... Args>
62using DetectedOr = typename impl::Detector<Default, void, Trait, Args...>::type;
64
65template <typename T, typename U>
66using ExpectSame = std::enable_if_t<std::is_same_v<T, U>>;
67
68namespace impl {
69
70using std::begin;
71using std::end;
72
73template <template <typename...> typename Template, typename T>
74struct IsInstantiationOf : std::false_type {};
75
76template <template <typename...> typename Template, typename... Args>
77struct IsInstantiationOf<Template, Template<Args...>> : std::true_type {};
78
79template <typename T>
80using KeyType = typename T::key_type;
81
82template <typename T>
83using MappedType = typename T::mapped_type;
84
85template <typename T>
86using IsRange = ExpectSame<std::decay_t<decltype(begin(std::declval<T&>()))>,
87 std::decay_t<decltype(end(std::declval<T&>()))>>;
88
89template <typename T>
90using IteratorType = std::enable_if_t<kIsDetected<IsRange, T>,
91 decltype(begin(std::declval<T&>()))>;
92
93template <typename T>
94using RangeValueType =
95 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
96
97template <typename T>
98using IsOstreamWritable =
99 ExpectSame<decltype(std::declval<std::ostream&>()
100 << std::declval<const std::remove_reference_t<T>&>()),
101 std::ostream&>;
102
103template <typename T, typename U>
104using IsEqualityComparable =
105 ExpectSame<decltype(std::declval<const T&>() == std::declval<const U&>()),
106 bool>;
107
108template <typename T>
109using IsStdHashable =
110 ExpectSame<decltype(std::hash<T>{}(std::declval<const T&>())), size_t>;
111
112template <typename T>
113using IsSizable = decltype(std::size(std::declval<T>()));
114
115template <typename T>
116using ReserveResult = decltype(std::declval<T&>().reserve(1));
117
118template <typename T>
119using PushBackResult = decltype(std::declval<T&>().push_back({}));
120
121template <typename T>
122struct IsFixedSizeContainer : std::false_type {};
123
124// Boost and std arrays
125template <typename T, std::size_t Size,
126 template <typename, std::size_t> typename Array>
127struct IsFixedSizeContainer<Array<T, Size>>
128 : std::bool_constant<sizeof(Array<T, Size>) == sizeof(T) * Size> {};
129
130template <typename... Args>
131constexpr bool IsSingleRange() {
132 if constexpr (sizeof...(Args) == 1) {
133 return kIsDetected<IsRange, Args...>;
134 } else {
135 return false;
136 }
137}
138
139} // namespace impl
140
141template <template <typename...> typename Template, typename... Args>
142inline constexpr bool kIsInstantiationOf =
143 impl::IsInstantiationOf<Template, Args...>::value;
144
145template <typename T>
146inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
147
148template <typename T>
149inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
150
151template <typename T>
152inline constexpr bool kIsMap =
153 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
154 kIsDetected<impl::MappedType, T>;
155
156template <typename T>
157using MapKeyType = DetectedType<impl::KeyType, T>;
158
159template <typename T>
160using MapValueType = DetectedType<impl::MappedType, T>;
161
162template <typename T>
163using RangeValueType = DetectedType<impl::RangeValueType, T>;
164
165template <typename T>
166inline constexpr bool kIsRecursiveRange =
167 std::is_same_v<DetectedType<RangeValueType, T>, T>;
168
169template <typename T>
170inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
171
174template <typename T>
175inline constexpr bool kIsCharacter =
176 std::is_same_v<T, char> || std::is_same_v<T, wchar_t> ||
177 std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t>;
178
181template <typename T>
182inline constexpr bool kIsInteger =
183 std::is_integral_v<T> && !kIsCharacter<T> && !std::is_same_v<T, bool>;
184
185template <typename T>
186inline constexpr bool kIsOstreamWritable =
187 kIsDetected<impl::IsOstreamWritable, T>;
188
189template <typename T, typename U = T>
190inline constexpr bool kIsEqualityComparable =
191 kIsDetected<impl::IsEqualityComparable, T, U>;
192
193template <typename T>
194inline constexpr bool kIsStdHashable =
195 kIsDetected<impl::IsStdHashable, T> && kIsEqualityComparable<T>;
196
198template <typename T>
199inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
200
202template <typename T>
203inline constexpr bool kIsReservable = kIsDetected<impl::ReserveResult, T>;
204
206template <typename T>
207inline constexpr bool kIsPushBackable = kIsDetected<impl::PushBackResult, T>;
208
210template <typename T>
211inline constexpr bool kIsFixedSizeContainer =
212 impl::IsFixedSizeContainer<T>::value;
213
215template <typename T>
216auto Inserter(T& container) {
217 if constexpr (kIsPushBackable<T>) {
218 return std::back_inserter(container);
219 } else if constexpr (kIsFixedSizeContainer<T>) {
220 return container.begin();
221 } else {
222 return std::inserter(container, container.end());
223 }
224}
225
226} // namespace meta
227
228USERVER_NAMESPACE_END