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 <concepts>
8#include <iosfwd>
9#include <iterator>
10#include <optional>
11#include <type_traits>
12#include <vector>
13
14#include <userver/utils/meta_light.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace meta {
19
20namespace impl {
21
22using std::begin;
23using std::end;
24
25template <typename T>
26concept HasKeyType = requires { typename T::key_type; };
27
28template <typename T>
29concept HasMappedType = requires { typename T::mapped_type; };
30
31template <typename T>
32concept IsRange = requires(T& t) {
33 requires std::is_same_v<std::decay_t<decltype(begin(t))>, std::decay_t<decltype(end(t))>>;
34};
35
36template <IsRange T>
37using IteratorType = decltype(begin(std::declval<T&>()));
38
39template <typename T>
40using RangeValueType = typename std::iterator_traits<IteratorType<T>>::value_type;
41
42template <typename T>
43struct IsFixedSizeContainer : std::false_type {};
44
45// Boost and std arrays
46template <typename T, std::size_t Size, template <typename, std::size_t> typename Array>
47struct IsFixedSizeContainer<Array<T, Size>> : std::bool_constant<sizeof(Array<T, Size>) == sizeof(T) * Size> {};
48
49template <typename... Args>
50concept IsSingleRange = (sizeof...(Args) == 1) && (impl::IsRange<Args> && ...);
51
52} // namespace impl
53
54template <typename T>
55concept IsVector = kIsInstantiationOf<std::vector, T>;
56
57template <typename T>
58concept IsRange = impl::IsRange<T>;
59
60/// Returns true if T is an ordered or unordered map or multimap
61template <typename T>
62concept IsMap = IsRange<T> && requires {
63 typename T::key_type;
64 typename T::mapped_type;
65};
66
67/// Returns true if T is a map (but not a multimap!)
68template <typename T>
69concept IsUniqueMap = IsMap<T> && requires(T& map, typename T::key_type key) {
70 map[key]; // no operator[] in multimaps
71};
72
73template <impl::HasKeyType T>
74using MapKeyType = typename T::key_type;
75
76template <impl::HasMappedType T>
77using MapValueType = typename T::mapped_type;
78
79template <impl::IsRange T>
80using RangeValueType = impl::RangeValueType<T>;
81
82template <typename T>
83concept IsRecursiveRange = IsRange<T> && std::same_as<impl::RangeValueType<T>, T>;
84
85template <typename T>
86concept IsIterator = requires { typename std::iterator_traits<T>::iterator_category; };
87
88template <typename T>
89concept IsOptional = kIsInstantiationOf<std::optional, T>;
90
91template <typename T>
92concept IsOstreamWritable = requires(std::ostream& os, const std::remove_reference_t<T>& val) {
93 {
94 os << val
95 } -> std::same_as<std::ostream&>;
96};
97
98template <typename T>
99concept IsStdHashable = requires(const T& val) {
100 {
101 std::hash<T>{}(val)
102 } -> std::same_as<std::size_t>;
103} && std::equality_comparable<T>;
104
105/// @brief Check if std::size is applicable to container
106template <typename T>
107concept IsSizable = requires(T value) { std::size(value); };
108
109/// @brief Check if a container has `reserve`
110template <typename T>
111concept IsReservable = requires(T value) { value.reserve(1); };
112
113/// @brief Check if a container has 'push_back'
114template <typename T>
115concept IsPushBackable = requires(T value) { value.push_back({}); };
116
117/// @brief Check if a container has fixed size (e.g. std::array)
118template <typename T>
119concept IsFixedSizeContainer = impl::IsFixedSizeContainer<T>::value;
120
121/// @brief Returns default inserter for a container
122template <typename T>
123auto Inserter(T& container) {
124 if constexpr (IsPushBackable<T>) {
125 return std::back_inserter(container);
126 } else if constexpr (IsFixedSizeContainer<T>) {
127 return container.begin();
128 } else {
129 return std::inserter(container, container.end());
130 }
131}
132
133/// @deprecated Use @ref meta::IsVector instead.
134template <typename T>
135// NOLINTNEXTLINE(readability-identifier-naming)
136concept kIsVector = IsVector<T>;
137
138/// @deprecated Use @ref meta::IsRange instead.
139template <typename T>
140// NOLINTNEXTLINE(readability-identifier-naming)
141concept kIsRange = IsRange<T>;
142
143/// @deprecated Use @ref meta::IsMap instead.
144template <typename T>
145// NOLINTNEXTLINE(readability-identifier-naming)
146concept kIsMap = IsMap<T>;
147
148/// @deprecated Use @ref meta::IsOptional instead.
149template <typename T>
150// NOLINTNEXTLINE(readability-identifier-naming)
151concept kIsOptional = IsOptional<T>;
152
153/// @deprecated Use @ref meta::IsSizable instead.
154template <typename T>
155// NOLINTNEXTLINE(readability-identifier-naming)
156concept kIsSizable = IsSizable<T>;
157
158/// @deprecated Use @ref meta::IsReservable instead.
159template <typename T>
160// NOLINTNEXTLINE(readability-identifier-naming)
161concept kIsReservable = IsReservable<T>;
162
163} // namespace meta
164
165USERVER_NAMESPACE_END