14USERVER_NAMESPACE_BEGIN
32template <
typename Default,
typename AlwaysVoid,
33 template <
typename...>
typename Trait,
typename... Args>
38template <
typename Default,
template <
typename...>
typename Trait,
40struct Detector<Default,
utils::void_t<Trait<Args...>>, Trait, Args...> {
41 using type = Trait<Args...>;
47template <
template <
typename...>
typename Trait,
typename... Args>
49 typename impl::Detector<
NotDetected, void, Trait, Args...>::type,
54template <
template <
typename...>
typename Trait,
typename... Args>
56 typename impl::Detector<
NotDetected, void, Trait, Args...>::type;
60template <
typename Default,
template <
typename...>
typename Trait,
62using DetectedOr =
typename impl::Detector<Default, void, Trait, Args...>::type;
65template <
typename T,
typename U>
66using ExpectSame = std::enable_if_t<std::is_same_v<T, U>>;
73template <
template <
typename...>
typename Template,
typename T>
74struct IsInstantiationOf : std::false_type {};
76template <
template <
typename...>
typename Template,
typename... Args>
77struct IsInstantiationOf<Template, Template<Args...>> : std::true_type {};
80using KeyType =
typename T::key_type;
83using MappedType =
typename T::mapped_type;
86using IsRange = ExpectSame<std::decay_t<decltype(begin(std::declval<T&>()))>,
87 std::decay_t<decltype(end(std::declval<T&>()))>>;
90using IteratorType = std::enable_if_t<kIsDetected<IsRange, T>,
91 decltype(begin(std::declval<T&>()))>;
95 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
98using IsOstreamWritable =
99 ExpectSame<decltype(std::declval<std::ostream&>()
100 << std::declval<const std::remove_reference_t<T>&>()),
103template <
typename T,
typename U>
104using IsEqualityComparable =
105 ExpectSame<decltype(std::declval<const T&>() == std::declval<const U&>()),
110 ExpectSame<
decltype(std::hash<T>{}(std::declval<const T&>())),
size_t>;
113using IsSizable =
decltype(std::size(std::declval<T>()));
116using ReserveResult =
decltype(std::declval<T&>().reserve(1));
119using PushBackResult =
decltype(std::declval<T&>().push_back({}));
122struct IsFixedSizeContainer : std::false_type {};
125template <
typename T, std::size_t Size,
126 template <
typename, std::
size_t>
typename Array>
127struct IsFixedSizeContainer<Array<T, Size>>
128 : std::bool_constant<sizeof(Array<T, Size>) == sizeof(T) * Size> {};
130template <
typename... Args>
131constexpr bool IsSingleRange() {
132 if constexpr (
sizeof...(Args) == 1) {
141template <
template <
typename...>
typename Template,
typename... Args>
142inline constexpr bool kIsInstantiationOf =
143 impl::IsInstantiationOf<Template, Args...>::value;
146inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
149inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
152inline constexpr bool kIsMap =
153 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
154 kIsDetected<impl::MappedType, T>;
157using MapKeyType = DetectedType<impl::KeyType, T>;
160using MapValueType = DetectedType<impl::MappedType, T>;
163using RangeValueType = DetectedType<impl::RangeValueType, T>;
166inline constexpr bool kIsRecursiveRange =
167 std::is_same_v<DetectedType<RangeValueType, T>, T>;
170inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
176 std::is_same_v<T, char> || std::is_same_v<T, wchar_t> ||
177 std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t>;
183 std::is_integral_v<T> && !kIsCharacter<T> && !std::is_same_v<T, bool>;
186inline constexpr bool kIsOstreamWritable =
187 kIsDetected<impl::IsOstreamWritable, T>;
189template <
typename T,
typename U = T>
190inline constexpr bool kIsEqualityComparable =
191 kIsDetected<impl::IsEqualityComparable, T, U>;
194inline constexpr bool kIsStdHashable =
195 kIsDetected<impl::IsStdHashable, T> && kIsEqualityComparable<T>;
199inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
212 impl::IsFixedSizeContainer<T>::value;
217 if constexpr (kIsPushBackable<T>) {
218 return std::back_inserter(container);
219 }
else if constexpr (kIsFixedSizeContainer<T>) {
220 return container.begin();
222 return std::inserter(container, container.end());