userver: userver/utils/meta.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
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