#pragma once #include #include namespace c10::guts { /** * Access information about result type or arguments from a function type. * Example: * using A = function_traits::return_type // A == int * using A = function_traits::parameter_types::tuple_type * // A == tuple */ template struct function_traits { static_assert( !std::is_same_v, "In function_traits, Func must be a plain function type."); }; template struct function_traits { using func_type = Result(Args...); using return_type = Result; using parameter_types = typelist::typelist; static constexpr auto number_of_parameters = sizeof...(Args); }; /** * infer_function_traits: creates a `function_traits` type for a simple * function (pointer) or functor (lambda/struct). Currently does not support * class methods. */ template struct infer_function_traits { using type = function_traits< c10::guts::detail::strip_class_t>; }; template struct infer_function_traits { using type = function_traits; }; template struct infer_function_traits { using type = function_traits; }; template using infer_function_traits_t = typename infer_function_traits::type; /** * make_function_traits: creates a `function_traits` type given a Return type * and a typelist of Argument types * * Example: * bool f(int, int); * * infer_function_traits_t == make_function_traits_t> */ template struct make_function_traits { static_assert( false_t::value, "In guts::make_function_traits, the ArgList argument must be typelist<...>."); }; template struct make_function_traits> { using type = function_traits; }; template using make_function_traits_t = typename make_function_traits::type; /** * make_offset_index_sequence * Like make_index_sequence, but starting from Start instead of 0. * * Example: * make_offset_index_sequence<10, 3> == std::index_sequence<10, 11, 12> */ template struct make_offset_index_sequence_impl : make_offset_index_sequence_impl { static_assert( static_cast(Start) >= 0, "make_offset_index_sequence: Start < 0"); static_assert(static_cast(N) >= 0, "make_offset_index_sequence: N < 0"); }; template struct make_offset_index_sequence_impl { typedef std::index_sequence type; }; template using make_offset_index_sequence = typename make_offset_index_sequence_impl::type; /** * Use tuple_elements to extract a position-indexed subset of elements * from the argument tuple into a result tuple. * * Example: * std::tuple t = std::make_tuple(0, "HEY", 2.0); * std::tuple result = tuple_elements(t, std::index_sequence<0, * 2>()); */ template constexpr auto tuple_elements(Tuple t, std::index_sequence) { return std::tuple...>(std::get(t)...); } /** * Use tuple_take to extract the first or last n elements from the argument * tuple into a result tuple. * * Example: * std::tuple t = std::make_tuple(0, "HEY", 2.0); * std::tuple first_two = tuple_take(t); * std::tuple last_two = tuple_take(t); */ template struct TupleTake {}; template struct TupleTake= 0, void>> { static auto call(Tuple t) { constexpr size_t size = std::tuple_size(); static_assert(N <= size, "tuple_take: N > size"); return tuple_elements(t, std::make_index_sequence{}); } }; template struct TupleTake < Tuple, N, std::enable_if_t> { static auto call(Tuple t) { constexpr size_t size = std::tuple_size(); static_assert(-N <= size, "tuple_take: -N > size"); return tuple_elements(t, make_offset_index_sequence{}); } }; template auto tuple_take(Tuple t) { return TupleTake::call(t); } /** * Use tuple_slice to extract a contiguous subtuple from the argument. * * Example: * std::tuple t = std::make_tuple(0, * "HEY", 2.0, false); std::tuple middle_two = * tuple_slice(t); */ template constexpr auto tuple_slice(Tuple t) { constexpr size_t size = std::tuple_size(); static_assert(Start + N <= size, "tuple_slice: Start + N > size"); return tuple_elements(t, make_offset_index_sequence{}); } /** * Use tuple_map to run a mapping function over a tuple to get a new tuple. * * Example 1: * auto result = tuple_map(std::tuple(3, 4, 5), [] * (int32_t a) -> int16_t {return a+1;}); * // result == std::tuple(4, 5, 6) * * Example 2: * struct Mapper { * std::string operator()(int32_t a) const { * return std::to_string(a); * } * int64_t operator()(const std::string& a) const { * return atoi(a.c_str()); * } * }; * auto result = tuple_map(std::tuple(3, "4"), * Mapper()); * // result == std::tuple("3", 4) * * Example 3: * struct A final { * int32_t func() { * return 5; * } * }; * struct B final { * std::string func() { * return "5"; * } * }; * auto result = tuple_map(std::make_tuple(A(), B()), [] (auto a) { return * a.func(); }); * // result == std::tuple(5, "5"); */ namespace detail { template auto tuple_map( // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) std::tuple&& tuple, const Mapper& mapper, std::index_sequence) { return std::tuple(std::get( tuple))))...>(mapper(std::forward(std::get(tuple)))...); } } // namespace detail template auto tuple_map(std::tuple&& tuple, const Mapper& mapper) { return detail::tuple_map( std::move(tuple), mapper, std::index_sequence_for()); } } // namespace c10::guts