diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 94d2701..5d0ed76 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(${PROJECT_NAME} test_operators.cpp test_sequence_range.cpp test_offset_getters.cpp + test_custom_type.cpp ) target_link_libraries(${PROJECT_NAME} diff --git a/test/unit/test_custom_type.cpp b/test/unit/test_custom_type.cpp new file mode 100644 index 0000000..fb85c43 --- /dev/null +++ b/test/unit/test_custom_type.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2015-2017 Michele "King_DuckZ" Santullo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "vectorwrapper/vectorwrapper.hpp" +#include "vectorwrapper/vector_cast.hpp" +#include +#include +#include +#include + +namespace { + int gcd (int a, int b) { + if ((a && b) == false) + return 0; + + int r, q, uRet; + + do { + uRet = b; + + q = a / b; + r = a - q * b; + + a = b; + b = r; + } while (r); + return uRet; + } + + class Rational { + public: + Rational() = default; + Rational (int num, int den) : m_n(num), m_d(den) {} + Rational (int num) : m_n(num), m_d(1) {} + Rational (const Rational&) = default; + Rational (Rational&&) = default; + ~Rational() = default; + + Rational& operator= (const Rational&) = default; + Rational& operator= (Rational&&) = default; + bool operator== (const Rational& o) const { return m_n == o.m_n and m_d == o.m_d; } + bool operator== (int o) const { return m_n == o and 1 == m_d; } + + operator float() const { return static_cast(m_n) / static_cast(m_d); } + + Rational& operator*= (const Rational& o) { + m_n *= o.m_n; m_d *= o.m_d; simplify(); return *this; + } + Rational& operator/= (const Rational& o) { + m_n *= o.m_d; m_d *= o.m_n; simplify(); return *this; + } + + int num() const { return m_n; } + int den() const { return m_d; } + + private: + void simplify() { const int t = gcd(m_n, m_d); m_n /= t; m_d /= t; } + + int m_n, m_d; + }; + + bool operator== (int a, const Rational& b) { + return a == b.num() and b.den() == 1; + } + + Rational operator* (Rational a, const Rational& b) { a *= b; return a; } + Rational operator/ (Rational a, const Rational& b) { a /= b; return a; } + + std::ostream& operator<< (std::ostream& os, const Rational& r) { + os << r.num() << '/' << r.den(); + return os; + } + + struct ThreeRationals { + Rational a, b, c; + }; +} //unnamed namespace + +namespace vwr { + template <> + struct VectorWrapperInfo { + enum { dimensions = 3 }; + typedef Rational scalar_type; + + enum { + offset_x = offsetof(ThreeRationals, a), + offset_y = offsetof(ThreeRationals, b), + offset_z = offsetof(ThreeRationals, c) + }; + }; + + template <> + struct VectorWrapperInfo > { + enum { dimensions = 3 }; + typedef float scalar_type; + + static scalar_type& get_at (size_type i, std::array& v) { + return v[i]; + } + }; +} //namespace vwr + +namespace { + typedef vwr::Vec rvec3; + typedef vwr::Vec > fvec3; +} //unnamed namespace + +TEST(vwr, custom_type) { + using vwr::vector_cast; + + rvec3 rational3( + Rational(1), + Rational(1, 2), + Rational(1, 3) + ); + + EXPECT_EQ(1, rational3.x()); + EXPECT_EQ(Rational(1, 2), rational3.y()); + EXPECT_EQ(Rational(1, 3), rational3.z()); + + fvec3 float3 = vector_cast(rational3); + EXPECT_EQ(1.0f, float3.x()); + EXPECT_EQ(0.5f, float3.y()); + + rational3 *= 4; + EXPECT_EQ(4, rational3.x()); + EXPECT_EQ(2, rational3.y()); + EXPECT_EQ(Rational(4, 3), rational3.z()); + + rational3 /= 2; + EXPECT_EQ(2, rational3.x()); + EXPECT_EQ(1, rational3.y()); + EXPECT_EQ(Rational(2, 3), rational3.z()); +}