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