lokinet/llarp/util/meta/traits.hpp

232 lines
6.6 KiB
C++
Raw Normal View History

2019-02-24 04:52:34 +00:00
#ifndef LLARP_TRAITS_HPP
#define LLARP_TRAITS_HPP
#include <cstddef>
2019-02-24 04:52:34 +00:00
#include <type_traits>
#include <utility>
2019-02-27 06:17:09 +00:00
#include <tuple>
2019-02-24 04:52:34 +00:00
namespace llarp
{
namespace traits
{
#ifdef __cpp_lib_void_t
using std::void_t;
#else
/// C++17 void_t backport
template <typename... Ts>
struct void_t_impl
{
using type = void;
};
template <typename... Ts>
using void_t = typename void_t_impl<Ts...>::type;
#endif
2019-02-24 04:52:34 +00:00
/// Represents the empty type
struct Bottom
{
};
/// Int tag
template <size_t N>
struct Tag
{
char arr[N + 1];
};
/// Type trait representing whether a type is pointer-like
template <typename T, typename _ = void>
struct is_pointy : public std::false_type
{
};
// We take the following things:
// - has element_type typedef
// - has dereference operator
// - has arrow operator
template <typename T>
struct is_pointy<T, std::conditional_t<false, void_t<decltype(*std::declval<T>())>, void>>
: public std::true_type
{
};
2019-02-24 04:52:34 +00:00
/// Type trait representing whether a type is an STL-style container
template <typename T, typename _ = void>
2019-02-24 04:52:34 +00:00
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,
void_t< typename T::value_type,
typename T::size_type,
typename T::iterator,
typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend()) >,
void > > : public std::true_type
{
};
// clang-format on
namespace Switch
{
template <size_t Selector, typename... Types>
2019-02-24 04:52:34 +00:00
struct Switch
{
using Type = Bottom;
};
template <typename T, typename... Types>
struct Switch<0u, T, Types...>
2019-02-24 04:52:34 +00:00
{
using Type = T;
};
template <size_t Selector, typename Tn, typename... Types>
struct Switch<Selector, Tn, Types...>
2019-02-24 04:52:34 +00:00
{
using Type = typename Switch<Selector - 1, Types...>::Type;
2019-02-24 04:52:34 +00:00
};
} // 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 <typename>
2019-02-24 04:52:34 +00:00
class False : public std::false_type
{
};
/// a case in the selection
template <template <typename...> class Trait = False>
2019-02-24 04:52:34 +00:00
class Case
{
public:
template <typename Type>
struct Selector : public Trait<Type>::type
2019-02-24 04:52:34 +00:00
{
};
using Type = Case;
};
// clang-format off
/// implementation helper
template < typename T,
template < typename... > class Trait1,
template < typename... > class Trait2,
template < typename... > class Trait3,
template < typename... > class Trait4,
template < typename... > class Trait5,
template < typename... > class Trait6,
template < typename... > class Trait7,
template < typename... > class Trait8,
template < typename... > class Trait9 >
2019-02-24 04:52:34 +00:00
struct SelectHelper {
enum {
Selector = (
Trait1<T>::value ? 1 :
Trait2<T>::value ? 2 :
Trait3<T>::value ? 3 :
Trait4<T>::value ? 4 :
Trait5<T>::value ? 5 :
Trait6<T>::value ? 6 :
Trait7<T>::value ? 7 :
Trait8<T>::value ? 8 :
Trait9<T>::value ? 9 : 0
)
};
using Type = typename Switch::Switch<
Selector,
Case<>,
Case<Trait1>,
Case<Trait2>,
Case<Trait3>,
Case<Trait4>,
Case<Trait5>,
Case<Trait6>,
Case<Trait7>,
Case<Trait8>,
Case<Trait9>
>::Type;
};
template< typename Type,
template < typename... > class Trait1,
template < typename... > class Trait2 = False,
template < typename... > class Trait3 = False,
template < typename... > class Trait4 = False,
template < typename... > class Trait5 = False,
template < typename... > class Trait6 = False,
template < typename... > class Trait7 = False,
template < typename... > class Trait8 = False,
template < typename... > class Trait9 = False >
2019-02-24 04:52:34 +00:00
struct Select : public SelectHelper< Type,
Trait1,
Trait2,
Trait3,
Trait4,
Trait5,
Trait6,
Trait7,
Trait8,
Trait9 >::Type
{
enum {
Selector = SelectHelper< Type,
Trait1,
Trait2,
Trait3,
Trait4,
Trait5,
Trait6,
Trait7,
Trait8,
Trait9 >::Selector
};
using SelectorType = std::integral_constant<int, Selector>;
};
// clang-format on
} // namespace select
namespace detail
{
template <typename T, typename F, size_t... Is>
void
for_each(T&& t, F f, std::index_sequence<Is...>)
{
auto l = {(f(std::get<Is>(t)), 0)...};
(void)l;
}
} // namespace detail
template <typename... Ts, typename F>
void
for_each_in_tuple(std::tuple<Ts...> const& t, F f)
{
detail::for_each(t, f, std::make_index_sequence<sizeof...(Ts)>());
}
} // namespace traits
2019-02-24 04:52:34 +00:00
} // namespace llarp
#endif