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&>()))>;
40 typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
43using OstreamWriteResult =
44 decltype(std::declval<std::ostream&>()
45 << std::declval<
const std::remove_reference_t<T>&>());
47template <
typename T,
typename U>
48using EqualityComparisonResult =
49 decltype(std::declval<
const T&>() == std::declval<
const U&>());
52using StdHashResult =
decltype(std::hash<T>{}(std::declval<
const T&>()));
55using IsSizable =
decltype(std::size(std::declval<T>()));
58using ReserveResult =
decltype(std::declval<T&>().reserve(1));
62 decltype(std::declval<
const T&>().at(std::declval<
typename T::key_type>()));
65using SubscriptOperatorResult =
66 decltype(std::declval<T>()[std::declval<
typename T::key_type>()]);
69using PushBackResult =
decltype(std::declval<T&>().push_back({}));
72struct IsFixedSizeContainer : std::false_type {};
75template <
typename T, std::size_t Size,
76 template <
typename, std::size_t>
typename Array>
77struct IsFixedSizeContainer<Array<T, Size>>
78 : std::bool_constant<
sizeof(Array<T, Size>) ==
sizeof(T) * Size> {};
80template <
typename... Args>
81constexpr bool IsSingleRange() {
82 if constexpr (
sizeof...(Args) == 1) {
83 return kIsDetected<IsRange, Args...>;
92inline constexpr bool kIsVector = kIsInstantiationOf<std::vector, T>;
95inline constexpr bool kIsRange = kIsDetected<impl::IsRange, T>;
100 kIsDetected<impl::IsRange, T> && kIsDetected<impl::KeyType, T> &&
101 kIsDetected<impl::MappedType, T>;
106 kIsMap<T> && kIsDetected<impl::SubscriptOperatorResult,
110using MapKeyType = DetectedType<impl::KeyType, T>;
113using MapValueType = DetectedType<impl::MappedType, T>;
116using RangeValueType = DetectedType<impl::RangeValueType, T>;
119inline constexpr bool kIsRecursiveRange =
120 std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
123inline constexpr bool kIsOptional = kIsInstantiationOf<std::optional, T>;
126inline constexpr bool kIsOstreamWritable =
127 std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
129template <
typename T,
typename U = T>
130inline constexpr bool kIsEqualityComparable =
131 std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>,
bool>;
134inline constexpr bool kIsStdHashable =
135 std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t> &&
136 kIsEqualityComparable<T>;
140inline constexpr bool kIsSizable = kIsDetected<impl::IsSizable, T>;
158 if constexpr (kIsPushBackable<T>) {
159 return std::back_inserter(container);
160 }
else if constexpr (kIsFixedSizeContainer<T>) {
161 return container.begin();
163 return std::inserter(container, container.end());