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>
39using RangeValueType =
40 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
41
42template <typename T>
43using OstreamWriteResult =
44 decltype(std::declval<std::ostream&>()
45 << std::declval<const std::remove_reference_t<T>&>());
46
47template <typename T, typename U>
48using EqualityComparisonResult =
49 decltype(std::declval<const T&>() == std::declval<const U&>());
50
51template <typename T>
52using StdHashResult = decltype(std::hash<T>{}(std::declval<const T&>()));
53
54template <typename T>
55using IsSizable = decltype(std::size(std::declval<T>()));
56
57template <typename T>
58using ReserveResult = decltype(std::declval<T&>().reserve(1));
59
60template <typename T>
61using AtResult =
62 decltype(std::declval<const T&>().at(std::declval<typename T::key_type>()));
63
64template <typename T>
65using SubscriptOperatorResult =
66 decltype(std::declval<T>()[std::declval<typename T::key_type>()]);
67
68template <typename T>
69using PushBackResult = decltype(std::declval<T&>().push_back({}));
70
71template <typename T>
72struct IsFixedSizeContainer : std::false_type {};
73
74// Boost and std arrays
75template <typename T, std::size_t Size,
76 template <typename, std::size_t> typename Array>
77struct IsFixedSizeContainer<Array<T, Size>>
78 : std::bool_constant<sizeof(Array<T, Size>) == sizeof(T) * Size> {};
79
80template <typename... Args>
81constexpr bool IsSingleRange() {
82 if constexpr (sizeof...(Args) == 1) {
83 return kIsDetected<IsRange, Args...>;
84 } else {
85 return false;
86 }
87}
88
89} // namespace impl
90
91template <typename T>
92inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
93
94template <typename T>
95inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
96
97/// Returns true if T is an ordered or unordered map or multimap
98template <typename T>
99inline constexpr bool kIsMap =
100 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
101 kIsDetected<impl::MappedType, T>;
102
103/// Returns true if T is a map (but not a multimap!)
104template <typename T>
105inline constexpr bool kIsUniqueMap =
106 kIsMap<T> && kIsDetected<impl::SubscriptOperatorResult,
107 T>; // no operator[] in multimaps
108
109template <typename T>
110using MapKeyType = DetectedType<impl::KeyType, T>;
111
112template <typename T>
113using MapValueType = DetectedType<impl::MappedType, T>;
114
115template <typename T>
116using RangeValueType = DetectedType<impl::RangeValueType, T>;
117
118template <typename T>
119inline constexpr bool kIsRecursiveRange =
120 std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
121
122template <typename T>
123inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
124
125template <typename T>
126inline constexpr bool kIsOstreamWritable =
127 std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
128
129template <typename T, typename U = T>
130inline constexpr bool kIsEqualityComparable =
131 std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>, bool>;
132
133template <typename T>
134inline constexpr bool kIsStdHashable =
135 std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> &&
136 kIsEqualityComparable<T>;
137
138/// @brief Check if std::size is applicable to container
139template <typename T>
140inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
141
142/// @brief Check if a container has `reserve`
143template <typename T>
144inline constexpr bool kIsReservable = kIsDetected<impl::ReserveResult, T>;
145
146/// @brief Check if a container has 'push_back'
147template <typename T>
148inline constexpr bool kIsPushBackable = kIsDetected<impl::PushBackResult, T>;
149
150/// @brief Check if a container has fixed size (e.g. std::array)
151template <typename T>
152inline constexpr bool kIsFixedSizeContainer =
154
155/// @brief Returns default inserter for a container
156template <typename T>
157auto Inserter(T& container) {
158 if constexpr (kIsPushBackable<T>) {
159 return std::back_inserter(container);
160 } else if constexpr (kIsFixedSizeContainer<T>) {
161 return container.begin();
162 } else {
163 return std::inserter(container, container.end());
164 }
165}
166
167} // namespace meta
168
169USERVER_NAMESPACE_END