coord: use consistent technique for assignment operators

This commit is contained in:
Danny Robson 2018-01-16 13:31:37 +11:00
parent e2f0d23a6d
commit 959617277f

View File

@ -48,35 +48,78 @@ namespace util {
// specific template template parameters. but the introduction of // specific template template parameters. but the introduction of
// coordinate types that do not expose size or type information as template // coordinate types that do not expose size or type information as template
// parameters we can't rely on this mechanism anymore. // parameters we can't rely on this mechanism anymore.
template <typename, typename,typename=void>
struct ops {}; template <typename, typename, typename=void>
struct assignment {};
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// vector operators template <typename CoordA, typename CoordB>
template <typename ValueA, typename ValueB> struct assignment<
struct ops< CoordA,
ValueA, CoordB,
ValueB,
std::enable_if_t< std::enable_if_t<
is_coord_v<ValueA> && is_coord_v<CoordA> &&
is_coord_v<ValueB> && is_coord_v<CoordB> &&
arity<ValueA>::value == arity<ValueB>::value arity_v<CoordA> == arity_v<CoordB> &&
std::is_same_v<
typename CoordA::value_type,
std::common_type_t<
typename CoordA::value_type,
typename CoordB::value_type
>
>
, ,
void void
> >
> { > {
template <typename OpT> template <typename OperationT>
static constexpr ValueA& static constexpr CoordA&
assignment (OpT op, ValueA &a, ValueB b) eval (OperationT &&op, CoordA &a, const CoordB &b)
{ {
for (std::size_t i = 0; i < ValueA::elements; ++i) for (std::size_t i = 0; i < CoordA::elements; ++i)
a[i] = op (a[i], b[i]); a[i] = op (a[i], b[i]);
return a; return a;
} }
}; };
//-------------------------------------------------------------------------
// vector-scalar operations
template <
typename CoordT,
typename ScalarT
>
struct assignment<
CoordT,
ScalarT,
std::enable_if_t<
is_coord_v<CoordT> &&
!is_coord_v<ScalarT> &&
has_scalar_op_v<CoordT> &&
std::is_same_v<
typename CoordT::value_type,
std::common_type_t<
typename CoordT::value_type,
ScalarT
>
>
,
void
>
> {
// we allow scalar types which can be naturally promoted to the vector's
// value_type
template <typename OperationT>
static constexpr CoordT&
eval (OperationT &&op, CoordT &coord, const ScalarT scalar)
{
for (size_t i = 0; i < CoordT::elements; ++i)
coord[i] = op (coord[i], scalar);
return coord;
}
};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// create a coord from supplied arguments, optionally specifying the /// create a coord from supplied arguments, optionally specifying the
/// underlying type. /// underlying type.
@ -125,6 +168,7 @@ namespace util {
struct arithmetic {}; struct arithmetic {};
//-------------------------------------------------------------------------
template <typename CoordA, typename CoordB> template <typename CoordA, typename CoordB>
struct arithmetic< struct arithmetic<
CoordA, CoordA,
@ -155,6 +199,7 @@ namespace util {
}; };
//-------------------------------------------------------------------------
template <typename CoordT, typename ScalarT> template <typename CoordT, typename ScalarT>
struct arithmetic< struct arithmetic<
CoordT, CoordT,
@ -177,6 +222,7 @@ namespace util {
}; };
//-------------------------------------------------------------------------
template <typename ScalarT, typename CoordT> template <typename ScalarT, typename CoordT>
struct arithmetic< struct arithmetic<
ScalarT, ScalarT,
@ -200,46 +246,6 @@ namespace util {
//-------------------------------------------------------------------------
// vector-scalar operations
template <
typename CoordT,
typename ScalarT
>
struct ops<
CoordT,
ScalarT,
std::enable_if_t<
is_coord_v<CoordT> &&
!is_coord_v<ScalarT> &&
has_scalar_op_v<CoordT>
>
> {
// we allow scalar types which can be naturally promoted to the vector's
// value_type
template <
typename OpT,
typename = std::enable_if_t<
std::is_same_v<
typename CoordT::value_type,
std::common_type_t<
typename CoordT::value_type,
ScalarT
>
>,
void
>
>
static constexpr CoordT&
assignment (OpT &&op, CoordT &c, const ScalarT s)
{
for (size_t i = 0; i < CoordT::elements; ++i)
c[i] = op (c[i], s);
return c;
}
};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template < template <
typename A, typename A,
@ -321,10 +327,10 @@ namespace util {
constexpr auto constexpr auto
operator += (A &&a, B &&b) operator += (A &&a, B &&b)
{ {
return ops< return assignment<
std::decay_t<A>, std::decay_t<A>,
std::decay_t<B> std::decay_t<B>
>::template assignment (std::plus{}, a, b); >::eval (std::plus{}, a, b);
} }
@ -340,10 +346,10 @@ namespace util {
constexpr auto constexpr auto
operator -= (A &&a, B &&b) operator -= (A &&a, B &&b)
{ {
return ops< return assignment<
std::decay_t<A>, std::decay_t<A>,
std::decay_t<B> std::decay_t<B>
>::template assignment (std::minus{}, a, b); >::eval (std::minus{}, a, b);
} }
@ -359,10 +365,10 @@ namespace util {
constexpr auto constexpr auto
operator *= (A &&a, B &&b) operator *= (A &&a, B &&b)
{ {
return ops< return assignment<
std::decay_t<A>, std::decay_t<A>,
std::decay_t<B> std::decay_t<B>
>::template assignment (std::multiplies{}, a, b); >::eval (std::multiplies{}, a, b);
} }
@ -378,10 +384,10 @@ namespace util {
constexpr auto constexpr auto
operator /= (A &&a, B &&b) operator /= (A &&a, B &&b)
{ {
return ops< return assignment<
std::decay_t<A>, std::decay_t<A>,
std::decay_t<B> std::decay_t<B>
>::template assignment (std::divides{}, a, b); >::eval (std::divides{}, a, b);
} }