13#include <userver/utils/meta_light.hpp>
15USERVER_NAMESPACE_BEGIN
25using KeyType =
typename T::key_type;
28using MappedType =
typename T::mapped_type;
32 ExpectSame<std::decay_t<
decltype(begin(std::declval<T&>()))>, std::decay_t<
decltype(end(std::declval<T&>()))>>;
35using IteratorType = std::enable_if_t<kIsDetected<IsRange, T>,
decltype(begin(std::declval<T&>()))>;
37template <
typename T,
typename =
void>
38struct IsIterator : std::false_type {};
41struct IsIterator<T, std::void_t<
typename std::iterator_traits<T>::iterator_category>> : std::true_type {};
44using RangeValueType =
typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
47using OstreamWriteResult =
decltype(std::declval<std::ostream&>() << std::declval<
const std::remove_reference_t<T>&>());
49template <
typename T,
typename U>
50using EqualityComparisonResult =
decltype(std::declval<
const T&>() == std::declval<
const U&>());
53using StdHashResult =
decltype(std::hash<T>{}(std::declval<
const T&>()));
56using IsSizable =
decltype(std::size(std::declval<T>()));
59using ReserveResult =
decltype(std::declval<T&>().reserve(1));
62using AtResult =
decltype(std::declval<
const T&>().at(std::declval<
typename T::key_type>()));
65using SubscriptOperatorResult =
decltype(std::declval<T>()[std::declval<
typename T::key_type>()]);
68using PushBackResult =
decltype(std::declval<T&>().push_back({}));
71struct IsFixedSizeContainer : std::false_type {};
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> {};
77template <
typename... Args>
78constexpr bool IsSingleRange() {
79 if constexpr (
sizeof...(Args) == 1) {
80 return kIsDetected<IsRange, Args...>;
89inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
92inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
97 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> && kIsDetected<impl::MappedType, T>;
102 impl::SubscriptOperatorResult,
106using MapKeyType = DetectedType<impl::KeyType, T>;
109using MapValueType = DetectedType<impl::MappedType, T>;
112using RangeValueType = DetectedType<impl::RangeValueType, T>;
115inline constexpr bool kIsRecursiveRange = std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
118inline constexpr bool kIsIterator = impl::IsIterator<T>::value;
121inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
124inline constexpr bool kIsOstreamWritable = std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
126template <
typename T,
typename U = T>
127inline constexpr bool kIsEqualityComparable = std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>,
bool>;
130inline constexpr bool kIsStdHashable =
131 std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> && kIsEqualityComparable<T>;
135inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
152 if constexpr (kIsPushBackable<T>) {
153 return std::back_inserter(container);
154 }
else if constexpr (kIsFixedSizeContainer<T>) {
155 return container.begin();
157 return std::inserter(container, container.end());