/* * Copyright 2015-2020 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()); }