|
|
#pragma once
|
|
|
|
|
|
#include <c10/util/TypeList.h>
|
|
|
#include <type_traits>
|
|
|
|
|
|
namespace c10::guts {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Func>
|
|
|
struct function_traits {
|
|
|
static_assert(
|
|
|
!std::is_same_v<Func, Func>,
|
|
|
"In function_traits<Func>, Func must be a plain function type.");
|
|
|
};
|
|
|
template <class Result, class... Args>
|
|
|
struct function_traits<Result(Args...)> {
|
|
|
using func_type = Result(Args...);
|
|
|
using return_type = Result;
|
|
|
using parameter_types = typelist::typelist<Args...>;
|
|
|
static constexpr auto number_of_parameters = sizeof...(Args);
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Functor>
|
|
|
struct infer_function_traits {
|
|
|
using type = function_traits<
|
|
|
c10::guts::detail::strip_class_t<decltype(&Functor::operator())>>;
|
|
|
};
|
|
|
|
|
|
template <typename Result, typename... Args>
|
|
|
struct infer_function_traits<Result (*)(Args...)> {
|
|
|
using type = function_traits<Result(Args...)>;
|
|
|
};
|
|
|
|
|
|
template <typename Result, typename... Args>
|
|
|
struct infer_function_traits<Result(Args...)> {
|
|
|
using type = function_traits<Result(Args...)>;
|
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
|
using infer_function_traits_t = typename infer_function_traits<T>::type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Result, typename ArgList>
|
|
|
struct make_function_traits {
|
|
|
static_assert(
|
|
|
false_t<ArgList>::value,
|
|
|
"In guts::make_function_traits<Result, TypeList>, the ArgList argument must be typelist<...>.");
|
|
|
};
|
|
|
|
|
|
template <typename Result, typename... Args>
|
|
|
struct make_function_traits<Result, typelist::typelist<Args...>> {
|
|
|
using type = function_traits<Result(Args...)>;
|
|
|
};
|
|
|
|
|
|
template <typename Result, typename ArgList>
|
|
|
using make_function_traits_t =
|
|
|
typename make_function_traits<Result, ArgList>::type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <size_t Start, size_t N, size_t... Is>
|
|
|
struct make_offset_index_sequence_impl
|
|
|
: make_offset_index_sequence_impl<Start, N - 1, Start + N - 1, Is...> {
|
|
|
static_assert(
|
|
|
static_cast<int>(Start) >= 0,
|
|
|
"make_offset_index_sequence: Start < 0");
|
|
|
static_assert(static_cast<int>(N) >= 0, "make_offset_index_sequence: N < 0");
|
|
|
};
|
|
|
|
|
|
template <size_t Start, size_t... Is>
|
|
|
struct make_offset_index_sequence_impl<Start, 0, Is...> {
|
|
|
typedef std::index_sequence<Is...> type;
|
|
|
};
|
|
|
|
|
|
template <size_t Start, size_t N>
|
|
|
using make_offset_index_sequence =
|
|
|
typename make_offset_index_sequence_impl<Start, N>::type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Tuple, size_t... Is>
|
|
|
constexpr auto tuple_elements(Tuple t, std::index_sequence<Is...>) {
|
|
|
return std::tuple<std::tuple_element_t<Is, Tuple>...>(std::get<Is>(t)...);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Tuple, int N, class Enable = void>
|
|
|
struct TupleTake {};
|
|
|
|
|
|
template <class Tuple, int N>
|
|
|
struct TupleTake<Tuple, N, std::enable_if_t<N >= 0, void>> {
|
|
|
static auto call(Tuple t) {
|
|
|
constexpr size_t size = std::tuple_size<Tuple>();
|
|
|
static_assert(N <= size, "tuple_take: N > size");
|
|
|
return tuple_elements(t, std::make_index_sequence<N>{});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
template <class Tuple, int N>
|
|
|
struct TupleTake < Tuple,
|
|
|
N, std::enable_if_t<N<0, void>> {
|
|
|
static auto call(Tuple t) {
|
|
|
constexpr size_t size = std::tuple_size<Tuple>();
|
|
|
static_assert(-N <= size, "tuple_take: -N > size");
|
|
|
return tuple_elements(t, make_offset_index_sequence<size + N, -N>{});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
template <class Tuple, int N>
|
|
|
auto tuple_take(Tuple t) {
|
|
|
return TupleTake<Tuple, N>::call(t);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Tuple, size_t Start, size_t N>
|
|
|
constexpr auto tuple_slice(Tuple t) {
|
|
|
constexpr size_t size = std::tuple_size<Tuple>();
|
|
|
static_assert(Start + N <= size, "tuple_slice: Start + N > size");
|
|
|
return tuple_elements(t, make_offset_index_sequence<Start, N>{});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
template <class Mapper, class... Args, size_t... Indices>
|
|
|
auto tuple_map(
|
|
|
|
|
|
std::tuple<Args...>&& tuple,
|
|
|
const Mapper& mapper,
|
|
|
std::index_sequence<Indices...>) {
|
|
|
return std::tuple<decltype(mapper(std::forward<Args>(std::get<Indices>(
|
|
|
tuple))))...>(mapper(std::forward<Args>(std::get<Indices>(tuple)))...);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
template <class Mapper, class... Args>
|
|
|
auto tuple_map(std::tuple<Args...>&& tuple, const Mapper& mapper) {
|
|
|
return detail::tuple_map(
|
|
|
std::move(tuple), mapper, std::index_sequence_for<Args...>());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|