mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-09 13:10:25 +00:00
227 lines
6.5 KiB
C++
227 lines
6.5 KiB
C++
#ifndef LLARP_TRAITS_HPP
|
|
#define LLARP_TRAITS_HPP
|
|
|
|
#include <absl/meta/type_traits.h>
|
|
|
|
#include <cstddef>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <tuple>
|
|
|
|
namespace llarp
|
|
{
|
|
namespace traits
|
|
{
|
|
using absl::conjunction;
|
|
using absl::disjunction;
|
|
using absl::void_t;
|
|
|
|
/// 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
|
|
{
|
|
};
|
|
|
|
/// Type trait representing whether a type is an STL-style container
|
|
template < typename T, typename _ = void >
|
|
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 >
|
|
struct Switch
|
|
{
|
|
using Type = Bottom;
|
|
};
|
|
|
|
template < typename T, typename... Types >
|
|
struct Switch< 0u, T, Types... >
|
|
{
|
|
using Type = T;
|
|
};
|
|
|
|
template < size_t Selector, typename Tn, typename... Types >
|
|
struct Switch< Selector, Tn, Types... >
|
|
{
|
|
using Type = typename Switch< Selector - 1, Types... >::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 < typename >
|
|
class False : public std::false_type
|
|
{
|
|
};
|
|
|
|
/// a case in the selection
|
|
template < template < typename... > class Trait = False >
|
|
class Case
|
|
{
|
|
public:
|
|
template < typename Type >
|
|
struct Selector : public Trait< Type >::type
|
|
{
|
|
};
|
|
|
|
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 >
|
|
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 >
|
|
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
|
|
} // namespace llarp
|
|
|
|
#endif
|