13#include <userver/utils/meta_light.hpp>
15USERVER_NAMESPACE_BEGIN
25using KeyType =
typename T::key_type;
28using MappedType =
typename T::mapped_type;
31using IsRange = ExpectSame<std::decay_t<
decltype(begin(std::declval<T&>()))>,
32 std::decay_t<
decltype(end(std::declval<T&>()))>>;
35using IteratorType = std::enable_if_t<kIsDetected<IsRange, T>,
36 decltype(begin(std::declval<T&>()))>;
38template <
typename T,
typename =
void>
39struct IsIterator : std::false_type {};
43 T, std::void_t<
typename std::iterator_traits<T>::iterator_category>>
48 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
51using OstreamWriteResult =
52 decltype(std::declval<std::ostream&>()
53 << std::declval<
const std::remove_reference_t<T>&>());
55template <
typename T,
typename U>
56using EqualityComparisonResult =
57 decltype(std::declval<
const T&>() == std::declval<
const U&>());
60using StdHashResult =
decltype(std::hash<T>{}(std::declval<
const T&>()));
63using IsSizable =
decltype(std::size(std::declval<T>()));
66using ReserveResult =
decltype(std::declval<T&>().reserve(1));
70 decltype(std::declval<
const T&>().at(std::declval<
typename T::key_type>()));
73using SubscriptOperatorResult =
74 decltype(std::declval<T>()[std::declval<
typename T::key_type>()]);
77using PushBackResult =
decltype(std::declval<T&>().push_back({}));
80struct IsFixedSizeContainer : std::false_type {};
83template <
typename T, std::size_t Size,
84 template <
typename, std::size_t>
typename Array>
85struct IsFixedSizeContainer<Array<T, Size>>
86 : std::bool_constant<
sizeof(Array<T, Size>) ==
sizeof(T) * Size> {};
88template <
typename... Args>
89constexpr bool IsSingleRange() {
90 if constexpr (
sizeof...(Args) == 1) {
91 return kIsDetected<IsRange, Args...>;
100inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
103inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
108 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
109 kIsDetected<impl::MappedType, T>;
114 kIsMap<T> && kIsDetected<impl::SubscriptOperatorResult,
118using MapKeyType = DetectedType<impl::KeyType, T>;
121using MapValueType = DetectedType<impl::MappedType, T>;
124using RangeValueType = DetectedType<impl::RangeValueType, T>;
127inline constexpr bool kIsRecursiveRange =
128 std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
131inline constexpr bool kIsIterator = impl::IsIterator<T>::value;
134inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
137inline constexpr bool kIsOstreamWritable =
138 std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
140template <
typename T,
typename U = T>
141inline constexpr bool kIsEqualityComparable =
142 std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>,
bool>;
145inline constexpr bool kIsStdHashable =
146 std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> &&
147 kIsEqualityComparable<T>;
151inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
169 if constexpr (kIsPushBackable<T>) {
170 return std::back_inserter(container);
171 }
else if constexpr (kIsFixedSizeContainer<T>) {
172 return container.begin();
174 return std::inserter(container, container.end());