From 2f4d31967541c9c4a87b2511fb0c6d3792c72c2d Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 8 Nov 2016 02:24:21 +0100 Subject: [PATCH] Implement binary operators. This also has the benefical side effect of ridding me of that stupid VWR_STATIC_CAST_RESULTS macro. --- README.md | 1 - include/vectorwrapper/vectorwrapper.hpp | 5 ++ include/vectorwrapper/vectorwrapper.inl | 93 +++++++++++-------------- test/unit/test_operators.cpp | 42 ++++++++++- test/unit_noconv/CMakeLists.txt | 4 -- 5 files changed, 87 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 7f65453..1b71b7d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ You still need to type some code in order to get started using the vector wrappe ## Features ## ### Build time configuration ### * 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(a+b). ### Automated conversion ### You can assign or construct a `Vec` from a `Vec`, 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. diff --git a/include/vectorwrapper/vectorwrapper.hpp b/include/vectorwrapper/vectorwrapper.hpp index 6e157a8..4a4fab6 100644 --- a/include/vectorwrapper/vectorwrapper.hpp +++ b/include/vectorwrapper/vectorwrapper.hpp @@ -296,6 +296,9 @@ namespace vwr { constexpr bool compare ( const Vec& parLeft, const Vec& parRight, Op parComposeOp, Op parOp, bt::number_seq ); template bool compare ( const Vec& parLeft, const Vec& parRight, ComposeOp parComposeOp, Op parOp, bt::number_seq ); + + template + Vec::type> binary_op ( const Vec& parLeft, const Vec& parRight, Op parOp, const Vec::type>& parLastVal, bt::number_seq ); } //namespace implem template @@ -429,6 +432,8 @@ namespace vwr { Vec::type> operator* ( const Vec& parLeft, const Vec& parRight ); template Vec::type> operator/ ( const Vec& parLeft, const Vec& parRight ); + template + Vec::type> operator% ( const Vec& parLeft, const Vec& parRight ); } //namespace vwr #include "vectorwrapper/vectorwrapper.inl" diff --git a/include/vectorwrapper/vectorwrapper.inl b/include/vectorwrapper/vectorwrapper.inl index b3f0f66..4f9da8c 100644 --- a/include/vectorwrapper/vectorwrapper.inl +++ b/include/vectorwrapper/vectorwrapper.inl @@ -291,6 +291,13 @@ namespace vwr { static_assert(I1 < VectorWrapperInfo::dimensions, "Index out of range"); return parComposeOp(parOp(parLeft[I1], parRight[I1]), compare(parLeft, parRight, parComposeOp, parOp, bt::number_seq())); } + + template + inline + Vec::type> binary_op (const Vec& parLeft, const Vec& parRight, Op parOp, bt::number_seq) { + typedef Vec::type> return_type; + return return_type(parOp(parLeft[I], parRight[I])...); + } } //namespace implem template const Vec Vec::unit_x(scalar_type(1)); @@ -414,70 +421,52 @@ namespace vwr { template inline Vec::type> operator+ (const Vec& parLeft, const Vec& parRight) { -#if defined(VWR_STATIC_CAST_RESULTS) - typedef typename VectorWrapperInfo::type>::scalar_type scalar_type; -#endif - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - Vec::type> retval; - for (size_type z = 0; z < VectorWrapperInfo::dimensions; ++z) { -#if defined(VWR_STATIC_CAST_RESULTS) - retval[z] = static_cast(parLeft[z] + parRight[z]); -#else - retval[z] = parLeft[z] + parRight[z]; -#endif - } - return retval; + return implem::binary_op( + parLeft, + parRight, + std::plus::scalar_type, typename VectorWrapperInfo::scalar_type>::type>(), + bt::number_range::dimensions>() + ); } template inline Vec::type> operator- (const Vec& parLeft, const Vec& parRight) { -#if defined(VWR_STATIC_CAST_RESULTS) - typedef typename VectorWrapperInfo::type>::scalar_type scalar_type; -#endif - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - Vec::type> retval; - for (size_type z = 0; z < VectorWrapperInfo::dimensions; ++z) { -#if defined(VWR_STATIC_CAST_RESULTS) - retval[z] = static_cast(parLeft[z] - parRight[z]); -#else - retval[z] = parLeft[z] - parRight[z]; -#endif - } - return retval; + return implem::binary_op( + parLeft, + parRight, + std::minus::scalar_type, typename VectorWrapperInfo::scalar_type>::type>(), + bt::number_range::dimensions>() + ); } template inline Vec::type> operator* (const Vec& parLeft, const Vec& parRight) { -#if defined(VWR_STATIC_CAST_RESULTS) - typedef typename VectorWrapperInfo::type>::scalar_type scalar_type; -#endif - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - Vec::type> retval; - for (size_type z = 0; z < VectorWrapperInfo::dimensions; ++z) { -#if defined(VWR_STATIC_CAST_RESULTS) - retval[z] = static_cast(parLeft[z] * parRight[z]); -#else - retval[z] = parLeft[z] * parRight[z]; -#endif - } - return retval; + return implem::binary_op( + parLeft, + parRight, + std::multiplies::scalar_type, typename VectorWrapperInfo::scalar_type>::type>(), + bt::number_range::dimensions>() + ); } template inline Vec::type> operator/ (const Vec& parLeft, const Vec& parRight) { -#if defined(VWR_STATIC_CAST_RESULTS) - typedef typename VectorWrapperInfo::type>::scalar_type scalar_type; -#endif - static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); - Vec::type> retval; - for (size_type z = 0; z < VectorWrapperInfo::dimensions; ++z) { -#if defined(VWR_STATIC_CAST_RESULTS) - retval[z] = static_cast(parLeft[z] / parRight[z]); -#else - retval[z] = parLeft[z] / parRight[z]; -#endif - } - return retval; + return implem::binary_op( + parLeft, + parRight, + std::divides::scalar_type, typename VectorWrapperInfo::scalar_type>::type>(), + bt::number_range::dimensions>() + ); + } + template + inline Vec::type> operator% (const Vec& parLeft, const Vec& parRight) { + static_assert(static_cast(VectorWrapperInfo::dimensions) == static_cast(VectorWrapperInfo::dimensions), "Dimensions mismatch"); + return implem::binary_op( + parLeft, + parRight, + std::modulus::scalar_type, typename VectorWrapperInfo::scalar_type>::type>(), + bt::number_range::dimensions>() + ); } } //namespace vwr diff --git a/test/unit/test_operators.cpp b/test/unit/test_operators.cpp index f773616..715c752 100644 --- a/test/unit/test_operators.cpp +++ b/test/unit/test_operators.cpp @@ -1,7 +1,7 @@ #include "sample_vectors.hpp" #include -TEST(vwr, operators) { +TEST(vwr, cmp_operators) { using namespace vwr; { @@ -42,3 +42,43 @@ TEST(vwr, operators) { 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); + } +} diff --git a/test/unit_noconv/CMakeLists.txt b/test/unit_noconv/CMakeLists.txt index 74ebc85..bb77de5 100644 --- a/test/unit_noconv/CMakeLists.txt +++ b/test/unit_noconv/CMakeLists.txt @@ -14,10 +14,6 @@ target_link_libraries(${PROJECT_NAME} 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 14)