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());