coord/ops: add elementwise apply

This commit is contained in:
Danny Robson 2018-03-13 14:34:58 +11:00
parent 16c6a6d627
commit 3e9e9bff5a

View File

@ -25,6 +25,7 @@
#include "../debug.hpp" #include "../debug.hpp"
#include "../maths.hpp" #include "../maths.hpp"
#include "../tuple.hpp"
#include "../preprocessor.hpp" #include "../preprocessor.hpp"
#include "../types/bits.hpp" #include "../types/bits.hpp"
@ -473,45 +474,77 @@ namespace util {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// logic operators
namespace detail { namespace detail {
/// invoke a function elementwise to the arguments elementwise.
///
/// \tparam ArgsT a tuple containing the (coord) arguments for the func
template < template <
typename RetT, typename RetT,
typename ArgT,
typename FuncT, typename FuncT,
std::size_t ...Indices, typename ArgsT,
typename = std::enable_if_t< std::size_t ...Indices
is_coord_v<ArgT> && is_coord_v<RetT>, void
>
> >
constexpr auto constexpr auto
apply (const std::index_sequence<Indices...>, apply (const std::index_sequence<Indices...>,
FuncT &&func, FuncT &&func,
const ArgT &a, ArgsT args) noexcept
const ArgT &b)
{ {
using part_t = std::tuple_element_t<0,ArgsT>;
using value_t = typename part_t::value_type;
return RetT { return RetT {
std::invoke (func, a[Indices], b[Indices])... std::apply (
func,
::util::tuple::convert (
static_cast<
const value_t& (&)(const part_t&)
> (
get<Indices,RetT>
), args
)
)...
}; };
} }
} }
//-------------------------------------------------------------------------
// invokes a function elementwise using elementwise parameters from the
// supplied arguments.
//
// equivalent to this pseduocode:
// for (int i: indices (ReturnT))
// res[i] = func (args[i]...);
// return res;
//
// forwards the arguments as a tuple to a helper function that has access
// to indices as a template parameter.
template < template <
typename RetT, typename ReturnT,
std::size_t S,
typename T,
template <std::size_t,typename> class ArgT,
typename FuncT, typename FuncT,
typename ...ArgT,
typename = std::enable_if_t< typename = std::enable_if_t<
is_coord_v<RetT> && is_coord_v<ArgT>, void // return type and arguments must be coordinates
(is_coord_v<ReturnT> && ... && is_coord_v<std::decay_t<ArgT>>) &&
// all types must be the same arity
((ReturnT::elements == std::decay_t<ArgT>::elements) && ...) &&
// all the arguments must be the same type
(std::is_same_v<
std::tuple_element_t<0,std::tuple<std::decay_t<ArgT>...>>,
std::decay_t<ArgT>
> && ...),
void
>, >,
typename Indices = std::make_index_sequence<S> typename Indices = std::make_index_sequence<ReturnT::elements>
> >
constexpr auto constexpr auto
apply (FuncT &&func, const ArgT<S,T> &a, const ArgT<S,T> &b) invoke (FuncT &&func, ArgT &&...args) noexcept
{ {
return detail::apply (Indices{}, std::forward<FuncT> (func), a, b); return detail::apply<ReturnT> (
Indices{},
std::forward<FuncT> (func),
std::tuple (std::forward<ArgT> (args)...)
);
} }