mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
e470a6d73e
- class template argument deduction lets us write `std::unique_lock foo{mutex}` instead of `std::unique_lock<mutex_type> foo{mutex}` which makes the `unique_lock` and `shared_lock` functions unnecessary. - Replace GNU-specific warn_unused_result attribute with C++17-standard [[nodiscard]] - Remove pre-C++17 workaround code for fold expressions, void_t
219 lines
6.3 KiB
C++
219 lines
6.3 KiB
C++
#ifndef LLARP_TRAITS_HPP
|
|
#define LLARP_TRAITS_HPP
|
|
|
|
#include <cstddef>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <tuple>
|
|
|
|
namespace llarp
|
|
{
|
|
namespace traits
|
|
{
|
|
/// 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, std::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,
|
|
std::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
|