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<IsDetected<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 IsDetected<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 = IsDetected<impl::IsRange, T>;
93
94/// Returns true if T is an ordered or unordered map or multimap
95template <typename T>
96inline constexpr bool
98
99/// Returns true if T is a map (but not a multimap!)
100template <typename T>
101inline constexpr bool kIsUniqueMap =
102 kIsMap<T> &&
105 T>; // no operator[] in multimaps
106
107template <typename T>
108using MapKeyType = DetectedType<impl::KeyType, T>;
109
110template <typename T>
111using MapValueType = DetectedType<impl::MappedType, T>;
112
113template <typename T>
114using RangeValueType = DetectedType<impl::RangeValueType, T>;
115
116template <typename T>
117inline constexpr bool kIsRecursiveRange = std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
118
119template <typename T>
120inline constexpr bool kIsIterator = impl::IsIterator<T>::value;
121
122template <typename T>
123inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
124
125template <typename T>
126inline constexpr bool kIsOstreamWritable = std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
127
128template <typename T, typename U = T>
129inline constexpr bool kIsEqualityComparable = std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>, bool>;
130
131template <typename T>
132inline constexpr bool
133 kIsStdHashable = std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> && kIsEqualityComparable<T>;
134
135/// @brief Check if std::size is applicable to container
136template <typename T>
137inline constexpr bool kIsSizable = IsDetected<impl::IsSizable, T>;
138
139/// @brief Check if a container has `reserve`
140template <typename T>
141inline constexpr bool kIsReservable = IsDetected<impl::ReserveResult, T>;
142
143/// @brief Check if a container has 'push_back'
144template <typename T>
145inline constexpr bool kIsPushBackable = IsDetected<impl::PushBackResult, T>;
146
147/// @brief Check if a container has fixed size (e.g. std::array)
148template <typename T>
150
151/// @brief Returns default inserter for a container
152template <typename T>
153auto Inserter(T& container) {
154 if constexpr (kIsPushBackable<T>) {
155 return std::back_inserter(container);
156 } else if constexpr (kIsFixedSizeContainer<T>) {
157 return container.begin();
158 } else {
159 return std::inserter(container, container.end());
160 }
161}
162
163} // namespace meta
164
165USERVER_NAMESPACE_END