#pragma once #include #include #include #include namespace llarp { namespace traits { /// Represents the empty type struct Bottom {}; /// Int tag template struct Tag { char arr[N + 1]; }; /// Type trait representing whether a type is pointer-like template struct is_pointy : public std::false_type {}; // We take the following things: // - has element_type typedef // - has dereference operator // - has arrow operator template struct is_pointy())>, void>> : public std::true_type {}; /// Type trait representing whether a type is an STL-style container template struct is_container : public std::false_type {}; // We take that the container has begin, end and size methods to be a // container. // clang-format off template < typename T > struct is_container< T, std::conditional_t< false, std::void_t< typename T::value_type, typename T::size_type, typename T::iterator, typename T::const_iterator, decltype(std::declval().size()), decltype(std::declval().begin()), decltype(std::declval().end()), decltype(std::declval().cbegin()), decltype(std::declval().cend()) >, void > > : public std::true_type { }; // clang-format on namespace Switch { template struct Switch { using Type = Bottom; }; template struct Switch<0u, T, Types...> { using Type = T; }; template struct Switch { using Type = typename Switch::Type; }; } // namespace Switch namespace select { /// This provides a way to do a compile-type dispatch based on type traits /// meta function which always returns false template class False : public std::false_type {}; /// a case in the selection template