Implement binary operators.
This also has the benefical side effect of ridding me of that stupid VWR_STATIC_CAST_RESULTS macro.
This commit is contained in:
parent
6bf3278631
commit
2f4d319675
5 changed files with 87 additions and 58 deletions
|
@ -29,7 +29,6 @@ You still need to type some code in order to get started using the vector wrappe
|
||||||
## Features ##
|
## Features ##
|
||||||
### Build time configuration ###
|
### Build time configuration ###
|
||||||
* VWR_WITH_IMPLICIT_CONVERSIONS (default: not defined) Enable implicit conversions between wrappers of vectors of different type (see Automated conversions).
|
* VWR_WITH_IMPLICIT_CONVERSIONS (default: not defined) Enable implicit conversions between wrappers of vectors of different type (see Automated conversions).
|
||||||
* VWR_STATIC_CAST_RESULTS (default: not defined) static_cast the result of binary operators in order to silence some compiler warnings. For example, when compiling with gcc -Wconvertion, given three short int variables a, b and c, c=a+b will generate a warning as a+b gets promoted into an int. Enabling this macro causes the previous example to become c=static_cast<short int>(a+b).
|
|
||||||
|
|
||||||
### Automated conversion ###
|
### Automated conversion ###
|
||||||
You can assign or construct a `Vec<A>` from a `Vec<B>`, provided they have the same dimensions and the assignemnt operator is able to convert B's scalar type to that of A. You need to define VWR_WITH_IMPLICIT_CONVERSIONS for this to work.
|
You can assign or construct a `Vec<A>` from a `Vec<B>`, provided they have the same dimensions and the assignemnt operator is able to convert B's scalar type to that of A. You need to define VWR_WITH_IMPLICIT_CONVERSIONS for this to work.
|
||||||
|
|
|
@ -296,6 +296,9 @@ namespace vwr {
|
||||||
constexpr bool compare ( const Vec<V1>& parLeft, const Vec<V2>& parRight, Op parComposeOp, Op parOp, bt::number_seq<size_type> );
|
constexpr bool compare ( const Vec<V1>& parLeft, const Vec<V2>& parRight, Op parComposeOp, Op parOp, bt::number_seq<size_type> );
|
||||||
template <bool LastVal, typename V1, typename V2, typename ComposeOp, typename Op, size_type I1, size_type... I>
|
template <bool LastVal, typename V1, typename V2, typename ComposeOp, typename Op, size_type I1, size_type... I>
|
||||||
bool compare ( const Vec<V1>& parLeft, const Vec<V2>& parRight, ComposeOp parComposeOp, Op parOp, bt::number_seq<size_type, I1, I...> );
|
bool compare ( const Vec<V1>& parLeft, const Vec<V2>& parRight, ComposeOp parComposeOp, Op parOp, bt::number_seq<size_type, I1, I...> );
|
||||||
|
|
||||||
|
template <typename V1, typename V2, typename Op, size_type... I>
|
||||||
|
Vec<typename std::common_type<V1, V2>::type> binary_op ( const Vec<V1>& parLeft, const Vec<V2>& parRight, Op parOp, const Vec<typename std::common_type<V1, V2>::type>& parLastVal, bt::number_seq<size_type, I...> );
|
||||||
} //namespace implem
|
} //namespace implem
|
||||||
|
|
||||||
template <typename V, size_type S>
|
template <typename V, size_type S>
|
||||||
|
@ -429,6 +432,8 @@ namespace vwr {
|
||||||
Vec<typename std::common_type<V1, V2>::type> operator* ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
|
Vec<typename std::common_type<V1, V2>::type> operator* ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
|
||||||
template <typename V1, typename V2>
|
template <typename V1, typename V2>
|
||||||
Vec<typename std::common_type<V1, V2>::type> operator/ ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
|
Vec<typename std::common_type<V1, V2>::type> operator/ ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
|
||||||
|
template <typename V1, typename V2>
|
||||||
|
Vec<typename std::common_type<V1, V2>::type> operator% ( const Vec<V1>& parLeft, const Vec<V2>& parRight );
|
||||||
} //namespace vwr
|
} //namespace vwr
|
||||||
|
|
||||||
#include "vectorwrapper/vectorwrapper.inl"
|
#include "vectorwrapper/vectorwrapper.inl"
|
||||||
|
|
|
@ -291,6 +291,13 @@ namespace vwr {
|
||||||
static_assert(I1 < VectorWrapperInfo<V1>::dimensions, "Index out of range");
|
static_assert(I1 < VectorWrapperInfo<V1>::dimensions, "Index out of range");
|
||||||
return parComposeOp(parOp(parLeft[I1], parRight[I1]), compare<LastVal>(parLeft, parRight, parComposeOp, parOp, bt::number_seq<size_type, I...>()));
|
return parComposeOp(parOp(parLeft[I1], parRight[I1]), compare<LastVal>(parLeft, parRight, parComposeOp, parOp, bt::number_seq<size_type, I...>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename V1, typename V2, typename Op, size_type... I>
|
||||||
|
inline
|
||||||
|
Vec<typename std::common_type<V1, V2>::type> binary_op (const Vec<V1>& parLeft, const Vec<V2>& parRight, Op parOp, bt::number_seq<size_type, I...>) {
|
||||||
|
typedef Vec<typename std::common_type<V1, V2>::type> return_type;
|
||||||
|
return return_type(parOp(parLeft[I], parRight[I])...);
|
||||||
|
}
|
||||||
} //namespace implem
|
} //namespace implem
|
||||||
|
|
||||||
template <typename V> const Vec<V, 1> Vec<V, 1>::unit_x(scalar_type(1));
|
template <typename V> const Vec<V, 1> Vec<V, 1>::unit_x(scalar_type(1));
|
||||||
|
@ -414,70 +421,52 @@ namespace vwr {
|
||||||
|
|
||||||
template <typename V1, typename V2>
|
template <typename V1, typename V2>
|
||||||
inline Vec<typename std::common_type<V1, V2>::type> operator+ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
inline Vec<typename std::common_type<V1, V2>::type> operator+ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
|
||||||
typedef typename VectorWrapperInfo<typename std::common_type<V1, V2>::type>::scalar_type scalar_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
||||||
Vec<typename std::common_type<V1, V2>::type> retval;
|
return implem::binary_op(
|
||||||
for (size_type z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
|
parLeft,
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
parRight,
|
||||||
retval[z] = static_cast<scalar_type>(parLeft[z] + parRight[z]);
|
std::plus<typename std::common_type<typename VectorWrapperInfo<V1>::scalar_type, typename VectorWrapperInfo<V2>::scalar_type>::type>(),
|
||||||
#else
|
bt::number_range<size_type, 0, VectorWrapperInfo<V1>::dimensions>()
|
||||||
retval[z] = parLeft[z] + parRight[z];
|
);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
template <typename V1, typename V2>
|
template <typename V1, typename V2>
|
||||||
inline Vec<typename std::common_type<V1, V2>::type> operator- (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
inline Vec<typename std::common_type<V1, V2>::type> operator- (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
|
||||||
typedef typename VectorWrapperInfo<typename std::common_type<V1, V2>::type>::scalar_type scalar_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
||||||
Vec<typename std::common_type<V1, V2>::type> retval;
|
return implem::binary_op(
|
||||||
for (size_type z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
|
parLeft,
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
parRight,
|
||||||
retval[z] = static_cast<scalar_type>(parLeft[z] - parRight[z]);
|
std::minus<typename std::common_type<typename VectorWrapperInfo<V1>::scalar_type, typename VectorWrapperInfo<V2>::scalar_type>::type>(),
|
||||||
#else
|
bt::number_range<size_type, 0, VectorWrapperInfo<V1>::dimensions>()
|
||||||
retval[z] = parLeft[z] - parRight[z];
|
);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
template <typename V1, typename V2>
|
template <typename V1, typename V2>
|
||||||
inline Vec<typename std::common_type<V1, V2>::type> operator* (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
inline Vec<typename std::common_type<V1, V2>::type> operator* (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
|
||||||
typedef typename VectorWrapperInfo<typename std::common_type<V1, V2>::type>::scalar_type scalar_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
||||||
Vec<typename std::common_type<V1, V2>::type> retval;
|
return implem::binary_op(
|
||||||
for (size_type z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
|
parLeft,
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
parRight,
|
||||||
retval[z] = static_cast<scalar_type>(parLeft[z] * parRight[z]);
|
std::multiplies<typename std::common_type<typename VectorWrapperInfo<V1>::scalar_type, typename VectorWrapperInfo<V2>::scalar_type>::type>(),
|
||||||
#else
|
bt::number_range<size_type, 0, VectorWrapperInfo<V1>::dimensions>()
|
||||||
retval[z] = parLeft[z] * parRight[z];
|
);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
template <typename V1, typename V2>
|
template <typename V1, typename V2>
|
||||||
inline Vec<typename std::common_type<V1, V2>::type> operator/ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
inline Vec<typename std::common_type<V1, V2>::type> operator/ (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
|
||||||
typedef typename VectorWrapperInfo<typename std::common_type<V1, V2>::type>::scalar_type scalar_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
||||||
Vec<typename std::common_type<V1, V2>::type> retval;
|
return implem::binary_op(
|
||||||
for (size_type z = 0; z < VectorWrapperInfo<V1>::dimensions; ++z) {
|
parLeft,
|
||||||
#if defined(VWR_STATIC_CAST_RESULTS)
|
parRight,
|
||||||
retval[z] = static_cast<scalar_type>(parLeft[z] / parRight[z]);
|
std::divides<typename std::common_type<typename VectorWrapperInfo<V1>::scalar_type, typename VectorWrapperInfo<V2>::scalar_type>::type>(),
|
||||||
#else
|
bt::number_range<size_type, 0, VectorWrapperInfo<V1>::dimensions>()
|
||||||
retval[z] = parLeft[z] / parRight[z];
|
);
|
||||||
#endif
|
}
|
||||||
}
|
template <typename V1, typename V2>
|
||||||
return retval;
|
inline Vec<typename std::common_type<V1, V2>::type> operator% (const Vec<V1>& parLeft, const Vec<V2>& parRight) {
|
||||||
|
static_assert(static_cast<int>(VectorWrapperInfo<V1>::dimensions) == static_cast<int>(VectorWrapperInfo<V2>::dimensions), "Dimensions mismatch");
|
||||||
|
return implem::binary_op(
|
||||||
|
parLeft,
|
||||||
|
parRight,
|
||||||
|
std::modulus<typename std::common_type<typename VectorWrapperInfo<V1>::scalar_type, typename VectorWrapperInfo<V2>::scalar_type>::type>(),
|
||||||
|
bt::number_range<size_type, 0, VectorWrapperInfo<V1>::dimensions>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} //namespace vwr
|
} //namespace vwr
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "sample_vectors.hpp"
|
#include "sample_vectors.hpp"
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
TEST(vwr, operators) {
|
TEST(vwr, cmp_operators) {
|
||||||
using namespace vwr;
|
using namespace vwr;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -42,3 +42,43 @@ TEST(vwr, operators) {
|
||||||
EXPECT_GE(b, a);
|
EXPECT_GE(b, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(vwr, bin_operators) {
|
||||||
|
using namespace vwr;
|
||||||
|
|
||||||
|
{
|
||||||
|
ivec3 a(0xFF, 0xAB, 0x10CE);
|
||||||
|
ivec3 b(0x45, 0xEE, 0x8);
|
||||||
|
ivec3 res(0xFF + 0x45, 0xAB + 0xEE, 0x10CE + 0x8);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, a + b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ivec3 a(0xFF, 0xAB, 0x10CE);
|
||||||
|
ivec3 b(0xC0, 0x0, 0xA);
|
||||||
|
ivec3 res(0xFF - 0xC0, 0xAB - 0x0, 0x10CE - 0xA);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, a - b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ivec3 a(0xFF, 0xAB, 0x10CE);
|
||||||
|
ivec3 b(0x3, 0x2, 0x1);
|
||||||
|
ivec3 res(0xFF * 0x3, 0xAB * 0x2, 0x10CE * 0x1);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, a * b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ivec3 a(0xFF, 0xAB, 0x10CE);
|
||||||
|
ivec3 b(0x3, 0x2, 0x1);
|
||||||
|
ivec3 res(0xFF / 0x3, 0xAB / 0x2, 0x10CE / 0x1);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, a / b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ivec3 a(0xE9, 0x104A, 0x28FF);
|
||||||
|
ivec3 b(0x15, 0x20, 0x1000);
|
||||||
|
ivec3 res(0xE9 % 0x15, 0x104A % 0x20, 0x28FF % 0x1000);
|
||||||
|
|
||||||
|
EXPECT_EQ(res, a % b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,10 +14,6 @@ target_link_libraries(${PROJECT_NAME}
|
||||||
gtest
|
gtest
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME}
|
|
||||||
PRIVATE VWR_STATIC_CAST_RESULTS
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
|
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
|
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue