userver: userver/storages/postgres/io/type_traits.hpp Source File
Loading...
Searching...
No Matches
type_traits.hpp
1#pragma once
2
3#include <iosfwd>
4#include <tuple>
5#include <type_traits>
6
7#include <userver/utils/meta.hpp>
8
9#include <userver/storages/postgres/detail/is_decl_complete.hpp>
10#include <userver/storages/postgres/io/io_fwd.hpp>
11#include <userver/storages/postgres/io/traits.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace storages::postgres::io::traits {
16
17template <bool Value>
18using BoolConstant = std::integral_constant<bool, Value>;
19template <std::size_t Value>
20using SizeConstant = std::integral_constant<std::size_t, Value>;
21
22///@{
23/** @name Type mapping traits */
24/// @brief Detect if the C++ type is mapped to a Postgres system type.
25template <typename T>
26struct IsMappedToSystemType : utils::IsDeclComplete<CppToSystemPg<T>> {};
27template <typename T>
28inline constexpr bool kIsMappedToSystemType = IsMappedToSystemType<T>::value;
29
30/// @brief Detect if the C++ type is mapped to a Postgres user type.
31template <typename T>
32struct IsMappedToUserType : utils::IsDeclComplete<CppToUserPg<T>> {};
33template <typename T>
34inline constexpr bool kIsMappedToUserType = IsMappedToUserType<T>::value;
35
36/// @brief Detect if the C++ type is mapped to a Postgres array type.
37template <typename T>
38struct IsMappedToArray;
39template <typename T>
40inline constexpr bool kIsMappedToArray = IsMappedToArray<T>::value;
41
42/// @brief Detect if the C++ type is mapped to a Postgres type.
43template <typename T, typename = USERVER_NAMESPACE::utils::void_t<>>
44struct IsMappedToPg : BoolConstant<kIsMappedToUserType<T> || kIsMappedToSystemType<T> || kIsMappedToArray<T>> {};
45template <typename T>
46inline constexpr bool kIsMappedToPg = IsMappedToPg<T>::value;
47
48/// @brief Mark C++ mapping a special case for disambiguation.
49template <typename T, typename = USERVER_NAMESPACE::utils::void_t<>>
50struct IsSpecialMapping : std::false_type {};
51template <typename T>
52inline constexpr bool kIsSpecialMapping = IsSpecialMapping<T>::value;
53///@}
54
55///@{
56/** @name Detect iostream operators */
57template <typename T>
58using HasOutputOperator = decltype(std::declval<std::ostream&>() << std::declval<T&>());
59
60template <typename T>
61inline constexpr bool kHasOutputOperator = meta::kIsDetected<HasOutputOperator, T>;
62
63template <typename T>
64using HasInputOperator = decltype(std::declval<std::istream&>() >> std::declval<T&>());
65
66template <typename T>
67inline constexpr bool kHasInputOperator = meta::kIsDetected<HasInputOperator, T>;
68///@}
69
70///@{
71/** @name Traits for containers */
72/// @brief Mark C++ container type as supported by the driver.
73template <typename T>
74struct IsCompatibleContainer : std::false_type {};
75template <typename T>
76inline constexpr bool kIsCompatibleContainer = IsCompatibleContainer<T>::value;
77
78template <typename T>
79inline constexpr bool kIsFixedSizeContainer = meta::kIsFixedSizeContainer<T>;
80/// @}
81
82///@{
83/// @brief Calculate number of dimensions in C++ container.
84template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
85struct DimensionCount : SizeConstant<0> {};
86
87template <typename T>
88struct DimensionCount<T, std::enable_if_t<kIsCompatibleContainer<T>>>
89 : SizeConstant<1 + DimensionCount<typename T::value_type>::value> {};
90template <typename T>
91inline constexpr std::size_t kDimensionCount = DimensionCount<T>::value;
92///@}
93
94///@{
95/// @brief Detect type of multidimensional C++ container.
96template <typename T>
97struct ContainerFinalElement;
98
99namespace detail {
100
101template <typename T>
102struct FinalElementImpl {
103 using type = T;
104};
105
106template <typename T>
107struct ContainerFinalElementImpl {
108 using type = typename ContainerFinalElement<typename T::value_type>::type;
109};
110
111} // namespace detail
112
113template <typename T>
114struct ContainerFinalElement
115 : std::conditional_t<kIsCompatibleContainer<T>, detail::ContainerFinalElementImpl<T>, detail::FinalElementImpl<T>> {
116};
117
118template <typename T>
119using ContainerFinaleElementType = typename ContainerFinalElement<T>::type;
120///@}
121
122///@{
123/** @name IsMappedToArray implementation */
124namespace detail {
125
126template <typename Container>
127constexpr bool EnableContainerMapping() {
128 if constexpr (!traits::kIsCompatibleContainer<Container>) {
129 return false;
130 } else {
131 return traits::kIsMappedToPg<typename traits::ContainerFinalElement<Container>::type>;
132 }
133}
134
135} // namespace detail
136
137template <typename T>
138struct IsMappedToArray : BoolConstant<detail::EnableContainerMapping<T>()> {};
139///@}
140
141template <typename T, typename = USERVER_NAMESPACE::utils::void_t<>>
142struct CanReserve : std::false_type {};
143template <typename T>
144struct CanReserve<T, USERVER_NAMESPACE::utils::void_t<decltype(std::declval<T>().reserve(std::declval<std::size_t>()))>>
145 : std::true_type {};
146template <typename T>
147inline constexpr bool kCanReserve = CanReserve<T>::value;
148
149template <typename T, typename = USERVER_NAMESPACE::utils::void_t<>>
150struct CanResize : std::false_type {};
151
152template <typename T>
153struct CanResize<T, USERVER_NAMESPACE::utils::void_t<decltype(std::declval<T>().resize(std::declval<std::size_t>()))>>
154 : std::true_type {};
155template <typename T>
156inline constexpr bool kCanResize = CanResize<T>::value;
157
158template <typename T, typename = USERVER_NAMESPACE::utils::void_t<>>
159struct CanClear : std::false_type {};
160
161template <typename T>
162struct CanClear<T, USERVER_NAMESPACE::utils::void_t<decltype(std::declval<T>().clear())>> : std::true_type {};
163template <typename T>
164inline constexpr bool kCanClear = CanClear<T>::value;
165
166template <typename T>
167auto Inserter(T& container) {
168 return meta::Inserter(container);
169}
170
171template <typename T>
172struct RemoveTupleReferences;
173
174template <typename... T>
175struct RemoveTupleReferences<std::tuple<T...>> {
176 using type = std::tuple<std::remove_reference_t<T>...>;
177};
178
179template <typename T>
180struct IsTupleOfRefs : std::false_type {};
181template <typename... T>
182struct IsTupleOfRefs<std::tuple<T&...>> : std::true_type {};
183
184template <typename T>
185struct AddTupleConstRef;
186
187template <typename... T>
188struct AddTupleConstRef<std::tuple<T...>> {
189 using type = std::tuple<std::add_const_t<std::add_lvalue_reference_t<std::decay_t<T>>>...>;
190};
191
192template <typename Tuple>
193struct TupleHasParsers;
194
195template <typename... T>
196struct TupleHasParsers<std::tuple<T...>> : std::bool_constant<(HasParser<std::decay_t<T>>::value && ...)> {};
197
198template <typename Tuple>
199struct TupleHasFormatters;
200
201template <typename... T>
202struct TupleHasFormatters<std::tuple<T...>> : std::bool_constant<(HasFormatter<std::decay_t<T>>::value && ...)> {};
203
204} // namespace storages::postgres::io::traits
205
206USERVER_NAMESPACE_END