Browse Source

Math: more Vector constexpr under C++14 rules

pull/597/head
Stanislaw Halik 4 years ago
parent
commit
5f1e2144d3
  1. 13
      src/Magnum/Math/Math.h
  2. 7
      src/Magnum/Math/Test/CMakeLists.txt
  3. 14
      src/Magnum/Math/Test/Cpp14VectorTest.h
  4. 34
      src/Magnum/Math/Test/Vector2Test.cpp
  5. 37
      src/Magnum/Math/Test/Vector3Test.cpp
  6. 55
      src/Magnum/Math/Test/Vector4Test.cpp
  7. 103
      src/Magnum/Math/Test/VectorTest.cpp
  8. 25
      src/Magnum/Math/TypeTraits.h
  9. 231
      src/Magnum/Math/Vector.h
  10. 12
      src/Magnum/Math/Vector2.h
  11. 18
      src/Magnum/Math/Vector3.h
  12. 26
      src/Magnum/Math/Vector4.h

13
src/Magnum/Math/Math.h

@ -116,4 +116,17 @@ namespace Implementation {
}}
// TODO remove this once corrade#152 gets merged
#if defined __cpp_constexpr && __cpp_constexpr >= 201304 || \
defined CORRADE_TARGET_MSVC && _MSC_VER >= 1910 && CORRADE_CXX_STANDARD >= 201402L
#define MAGNUM_CONSTEXPR14 constexpr
#else
#define MAGNUM_CONSTEXPR14
#endif
#if defined(__clang__) && __clang_major__ >= 9 || defined(__GNUG__) && __GNUG__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1931
#define MAGNUM_CONSTEVAL (__builtin_is_constant_evaluated())
#elif CORRADE_CXX_STANDARD >= 202002L
#define MAGNUM_CONSTEVAL (std::is_constant_evaluated())
#endif
#endif

7
src/Magnum/Math/Test/CMakeLists.txt

@ -41,6 +41,13 @@ corrade_add_test(MathVectorTest VectorTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector2Test Vector2Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector4Test Vector4Test.cpp LIBRARIES MagnumMathTestLib)
foreach(_test VectorTest Vector2Test Vector3Test Vector4Test)
corrade_add_test(Cpp14Math${_test} ${_test}.cpp LIBRARIES MagnumMathTestLib)
set_target_properties(Cpp14Math${_test} PROPERTIES CORRADE_CXX_STANDARD 14)
target_compile_definitions(Cpp14Math${_test} PRIVATE TESTING_CONSTEXPR CORRADE_GRACEFUL_ASSERT)
endforeach()
corrade_add_test(MathColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathRectangularMatrixTest RectangularMatrixTest.cpp LIBRARIES MagnumMathTestLib)

14
src/Magnum/Math/Test/Cpp14VectorTest.h

@ -0,0 +1,14 @@
#ifndef Magnum_Math_Test_Cpp14Vector
#define Magnum_Math_Test_Cpp14Vector
#define CE
#ifdef TESTING_CONSTEXPR
#if __cpp_constexpr >= 201304
#undef CE
#define CE constexpr
#else
#define SKIP_TESTING
#endif
#endif
#endif

34
src/Magnum/Math/Test/Vector2Test.cpp

@ -32,6 +32,8 @@
#include "Magnum/Math/StrictWeakOrdering.h"
#include "Magnum/Math/Swizzle.h"
#include "Cpp14VectorTest.h"
struct Vec2 {
float x, y;
};
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector2Test: Corrade::TestSuite::Tester {
explicit Vector2Test();
#ifndef SKIP_TESTING
void construct();
void constructDefault();
void constructNoInit();
@ -76,6 +79,9 @@ struct Vector2Test: Corrade::TestSuite::Tester {
void swizzleType();
void debug();
#else
void skipTesting();
#endif
};
typedef Math::Vector3<Int> Vector3i;
@ -83,7 +89,14 @@ typedef Math::Vector2<Float> Vector2;
typedef Math::Vector2<Int> Vector2i;
Vector2Test::Vector2Test() {
addTests({&Vector2Test::construct,
#ifndef TESTING_CONSTEXPR
setTestName("MathVector2Test");
#else
setTestName("Cpp14MathVector2Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector2Test::construct,
&Vector2Test::constructDefault,
&Vector2Test::constructNoInit,
&Vector2Test::constructOneValue,
@ -101,9 +114,15 @@ Vector2Test::Vector2Test() {
&Vector2Test::strictWeakOrdering,
&Vector2Test::swizzleType,
&Vector2Test::debug});
&Vector2Test::debug
#else
&Vector2Test::skipTesting
#endif
});
}
#ifndef SKIP_TESTING
void Vector2Test::construct() {
constexpr Vector2 a = {1.5f, 2.5f};
CORRADE_COMPARE(a, (Vector<2, Float>(1.5f, 2.5f)));
@ -197,7 +216,7 @@ void Vector2Test::convert() {
}
void Vector2Test::access() {
Vector2 vec(1.0f, -2.0f);
CE Vector2 vec(1.0f, -2.0f);
CORRADE_COMPARE(vec.x(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f);
@ -209,8 +228,8 @@ void Vector2Test::access() {
}
void Vector2Test::cross() {
Vector2i a(1, -1);
Vector2i b(4, 3);
CE Vector2i a(1, -1);
CE Vector2i b(4, 3);
CORRADE_COMPARE(Math::cross(a, b), 7);
CORRADE_COMPARE(Math::cross<Int>({a, 0}, {b, 0}), Vector3i(0, 0, Math::cross(a, b)));
@ -268,6 +287,11 @@ void Vector2Test::debug() {
Debug(&o) << Vector2(0.5f, 15.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15)\n");
}
#else
void Vector2Test::skipTesting() {
CORRADE_SKIP("Relaxed constexpr not supported by the compiler.");
}
#endif
}}}}

37
src/Magnum/Math/Test/Vector3Test.cpp

@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE.
*/
#include "Cpp14VectorTest.h"
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector3Test: Corrade::TestSuite::Tester {
explicit Vector3Test();
#ifndef SKIP_TESTING
void construct();
void constructDefault();
void constructNoInit();
@ -76,6 +79,9 @@ struct Vector3Test: Corrade::TestSuite::Tester {
void swizzleType();
void debug();
#else
void skipTesting();
#endif
};
typedef Math::Vector3<Float> Vector3;
@ -83,7 +89,14 @@ typedef Math::Vector3<Int> Vector3i;
typedef Math::Vector2<Float> Vector2;
Vector3Test::Vector3Test() {
addTests({&Vector3Test::construct,
#ifndef TESTING_CONSTEXPR
setTestName("MathVector3Test");
#else
setTestName("Cpp14MathVector3Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector3Test::construct,
&Vector3Test::constructDefault,
&Vector3Test::constructNoInit,
&Vector3Test::constructOneValue,
@ -101,9 +114,13 @@ Vector3Test::Vector3Test() {
&Vector3Test::strictWeakOrdering,
&Vector3Test::swizzleType,
&Vector3Test::debug});
&Vector3Test::debug
#else
&Vector3Test::skipTesting
#endif
});
}
#ifndef SKIP_TESTING
void Vector3Test::construct() {
constexpr Vector3 a = {1.0f, 2.5f, -3.0f};
CORRADE_COMPARE(a, (Vector<3, Float>(1.0f, 2.5f, -3.0f)));
@ -206,7 +223,7 @@ void Vector3Test::convert() {
}
void Vector3Test::access() {
Vector3 vec(1.0f, -2.0f, 5.0f);
CE Vector3 vec(1.0f, -2.0f, 5.0f);
CORRADE_COMPARE(vec.x(), 1.0f);
CORRADE_COMPARE(vec.r(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f);
@ -230,8 +247,8 @@ void Vector3Test::access() {
}
void Vector3Test::cross() {
Vector3i a(1, -1, 1);
Vector3i b(4, 3, 7);
CE Vector3i a(1, -1, 1);
CE Vector3i b(4, 3, 7);
CORRADE_COMPARE(Math::cross(a, b), Vector3i(-10, -3, 7));
}
@ -255,7 +272,7 @@ void Vector3Test::scales() {
}
void Vector3Test::twoComponent() {
Vector3 a(1.0f, 2.0f, 3.0f);
CE Vector3 a(1.0f, 2.0f, 3.0f);
CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f));
constexpr Vector3 b(1.0f, 2.0f, 3.0f);
@ -292,7 +309,11 @@ void Vector3Test::debug() {
Debug(&o) << Vector3(0.5f, 15.0f, 1.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1)\n");
}
#else
void Vector3Test::skipTesting() {
CORRADE_SKIP("Relaxed constexpr not supported by the compiler.");
}
#endif
}}}}
CORRADE_TEST_MAIN(Magnum::Math::Test::Vector3Test)

55
src/Magnum/Math/Test/Vector4Test.cpp

@ -32,6 +32,8 @@
#include "Magnum/Math/StrictWeakOrdering.h"
#include "Magnum/Math/Swizzle.h"
#include "Cpp14VectorTest.h"
struct Vec4 {
float x, y, z, w;
};
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector4Test: Corrade::TestSuite::Tester {
explicit Vector4Test();
#ifndef SKIP_TESTING
void construct();
void constructPad();
void constructDefault();
@ -78,6 +81,9 @@ struct Vector4Test: Corrade::TestSuite::Tester {
void swizzleType();
void debug();
#else
void skipTesting();
#endif
};
typedef Math::Vector4<Float> Vector4;
@ -86,7 +92,14 @@ typedef Math::Vector3<Float> Vector3;
typedef Math::Vector2<Float> Vector2;
Vector4Test::Vector4Test() {
addTests({&Vector4Test::construct,
#ifndef TESTING_CONSTEXPR
setTestName("MathVector4Test");
#else
setTestName("Cpp14MathVector4Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector4Test::construct,
&Vector4Test::constructPad,
&Vector4Test::constructDefault,
&Vector4Test::constructNoInit,
@ -106,9 +119,14 @@ Vector4Test::Vector4Test() {
&Vector4Test::strictWeakOrdering,
&Vector4Test::swizzleType,
&Vector4Test::debug});
&Vector4Test::debug
#else
&Vector4Test::skipTesting
#endif
});
}
#ifndef SKIP_TESTING
void Vector4Test::construct() {
constexpr Vector4 a = {1.0f, -2.5f, 3.0f, 4.1f};
CORRADE_COMPARE(a, (Vector<4, Float>(1.0f, -2.5f, 3.0f, 4.1f)));
@ -228,7 +246,7 @@ void Vector4Test::convert() {
}
void Vector4Test::access() {
Vector4 vec(1.0f, -2.0f, 5.0f, 0.5f);
CE Vector4 vec(1.0f, -2.0f, 5.0f, 0.5f);
CORRADE_COMPARE(vec.x(), 1.0f);
CORRADE_COMPARE(vec.r(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f);
@ -258,7 +276,7 @@ void Vector4Test::access() {
}
void Vector4Test::threeComponent() {
Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CE Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CORRADE_COMPARE(a.xyz(), Vector3(1.0f, 2.0f, 3.0f));
CORRADE_COMPARE(a.rgb(), Vector3(1.0f, 2.0f, 3.0f));
@ -270,7 +288,7 @@ void Vector4Test::threeComponent() {
}
void Vector4Test::twoComponent() {
Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CE Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f));
constexpr Vector4 b(1.0f, 2.0f, 3.0f, 4.0f);
@ -281,9 +299,9 @@ void Vector4Test::twoComponent() {
}
void Vector4Test::planeEquationThreePoints() {
const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f};
CE const Vector3 a{1.0f, 0.5f, 3.0f};
CE const Vector3 b{1.5f, 1.5f, 2.5f};
CE const Vector3 c{2.0f, 1.5f, 1.0f};
const Vector4 eq = Math::planeEquation(a, b, c);
CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f);
@ -296,12 +314,12 @@ void Vector4Test::planeEquationThreePoints() {
}
void Vector4Test::planeEquationNormalPoint() {
const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 normal{-0.9045340f, 0.3015113f, -0.3015113f};
const Vector4 eq = Math::planeEquation(normal, a);
CE const Vector3 a{1.0f, 0.5f, 3.0f};
CE const Vector3 normal{-0.9045340f, 0.3015113f, -0.3015113f};
CE const Vector4 eq = Math::planeEquation(normal, a);
const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f};
CE const Vector3 b{1.5f, 1.5f, 2.5f};
CE const Vector3 c{2.0f, 1.5f, 1.0f};
CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(b, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(c, eq.xyz()) + eq.w(), 0.0f);
@ -310,9 +328,9 @@ void Vector4Test::planeEquationNormalPoint() {
void Vector4Test::strictWeakOrdering() {
StrictWeakOrdering o;
const Vector4 v4a{1.0f, 2.0f, 3.0f, 4.0f};
const Vector4 v4b{2.0f, 3.0f, 4.0f, 5.0f};
const Vector4 v4c{1.0f, 2.0f, 3.0f, 5.0f};
CE const Vector4 v4a{1.0f, 2.0f, 3.0f, 4.0f};
CE const Vector4 v4b{2.0f, 3.0f, 4.0f, 5.0f};
CE const Vector4 v4c{1.0f, 2.0f, 3.0f, 5.0f};
CORRADE_VERIFY( o(v4a, v4b));
CORRADE_VERIFY(!o(v4b, v4a));
@ -335,6 +353,11 @@ void Vector4Test::debug() {
Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n");
}
#else
void Vector4Test::skipTesting() {
CORRADE_SKIP("Relaxed constexpr not supported by the compiler.");
}
#endif
}}}}

103
src/Magnum/Math/Test/VectorTest.cpp

@ -33,6 +33,8 @@
#include "Magnum/Math/Vector.h"
#include "Magnum/Math/StrictWeakOrdering.h"
#include "Cpp14VectorTest.h"
struct Vec3 {
float x, y, z;
};
@ -58,6 +60,7 @@ namespace Test { namespace {
struct VectorTest: Corrade::TestSuite::Tester {
explicit VectorTest();
#ifndef SKIP_TESTING
void construct();
void constructFromData();
void constructPad();
@ -119,6 +122,9 @@ struct VectorTest: Corrade::TestSuite::Tester {
void debug();
void debugPacked();
#else
void skipTesting();
#endif
};
typedef Math::Constants<Float> Constants;
@ -133,7 +139,14 @@ typedef Vector<4, Int> Vector4i;
using namespace Literals;
VectorTest::VectorTest() {
addTests({&VectorTest::construct,
#ifndef TESTING_CONSTEXPR
setTestName("MathVectorTest");
#else
setTestName("Cpp14MathVectorTest");
#endif
addTests({
#ifndef SKIP_TESTING
&VectorTest::construct,
&VectorTest::constructFromData,
&VectorTest::constructPad,
&VectorTest::constructPadDefaultHalf,
@ -193,9 +206,14 @@ VectorTest::VectorTest() {
&VectorTest::strictWeakOrdering,
&VectorTest::debug,
&VectorTest::debugPacked});
&VectorTest::debugPacked
#else
&VectorTest::skipTesting
#endif
});
}
#ifndef SKIP_TESTING
void VectorTest::construct() {
constexpr Vector4 a = {1.0f, 2.0f, -3.0f, 4.5f};
CORRADE_COMPARE(a, Vector4(1.0f, 2.0f, -3.0f, 4.5f));
@ -378,9 +396,9 @@ void VectorTest::compareComponentWise() {
typedef BitVector<3> BitVector3;
typedef BitVector<4> BitVector4;
Vector4 a{1.0f, -3.5f, 5.0f, -10.0f};
Vector4 b{1.0f + TypeTraits<Float>::epsilon()/2, -3.5f, 5.0f - TypeTraits<Float>::epsilon()*2, -10.0f};
Vector4 c{1.0f + TypeTraits<Float>::epsilon()*2, -3.5f, 5.0f - TypeTraits<Float>::epsilon()*10, -10.0f};
CE Vector4 a{1.0f, -3.5f, 5.0f, -10.0f};
CE Vector4 b{1.0f + TypeTraits<Float>::epsilon()/2, -3.5f, 5.0f - TypeTraits<Float>::epsilon()*2, -10.0f};
CE Vector4 c{1.0f + TypeTraits<Float>::epsilon()*2, -3.5f, 5.0f - TypeTraits<Float>::epsilon()*10, -10.0f};
CORRADE_COMPARE(equal(a, b), BitVector4{0xf});
CORRADE_COMPARE(equal(a, c), BitVector4{0xa});
CORRADE_COMPARE(notEqual(a, b), BitVector4{0x0});
@ -400,31 +418,31 @@ void VectorTest::promotedNegated() {
}
void VectorTest::addSubtract() {
Vector4 a(1.0f, -3.0f, 5.0f, -10.0f);
Vector4 b(7.5f, 33.0f, -15.0f, 0.0f);
Vector4 c(8.5f, 30.0f, -10.0f, -10.0f);
CE Vector4 a(1.0f, -3.0f, 5.0f, -10.0f);
CE Vector4 b(7.5f, 33.0f, -15.0f, 0.0f);
CE Vector4 c(8.5f, 30.0f, -10.0f, -10.0f);
CORRADE_COMPARE(a + b, c);
CORRADE_COMPARE(c - b, a);
}
void VectorTest::multiplyDivide() {
Vector4 vector(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CE Vector4 vector(1.0f, 2.0f, 3.0f, 4.0f);
CE Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vector*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vector, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vector);
/* Divide vector with number and invert */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CE Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
CE Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result);
}
void VectorTest::multiplyDivideIntegral() {
Vector4i vector(32, 10, -6, 2);
Vector4i multiplied(-48, -15, 9, -3);
CE Vector4i vector(32, 10, -6, 2);
CE Vector4i multiplied(-48, -15, 9, -3);
CORRADE_COMPARE(vector*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vector, multiplied);
@ -434,18 +452,18 @@ void VectorTest::multiplyDivideIntegral() {
}
void VectorTest::multiplyDivideComponentWise() {
Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f);
Vector4 multiplied(7.0f, -8.0f, -4.5f, 4.0f);
CE Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
CE Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f);
CE Vector4 multiplied(7.0f, -8.0f, -4.5f, 4.0f);
CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplied/multiplier, vec);
}
void VectorTest::multiplyDivideComponentWiseIntegral() {
Vector4i vec(7, 2, -16, -1);
Vector4 multiplier(2.0f, -1.5f, 0.5f, 10.0f);
Vector4i multiplied(14, -3, -8, -10);
CE Vector4i vec(7, 2, -16, -1);
CE Vector4 multiplier(2.0f, -1.5f, 0.5f, 10.0f);
CE Vector4i multiplied(14, -3, -8, -10);
CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplier*vec, multiplied);
@ -457,8 +475,8 @@ void VectorTest::multiplyDivideComponentWiseIntegral() {
void VectorTest::modulo() {
typedef Math::Vector<2, Int> Vector2i;
const Vector2i a(4, 13);
const Vector2i b(2, 5);
CE const Vector2i a(4, 13);
CE const Vector2i b(2, 5);
CORRADE_COMPARE(a % 2, Vector2i(0, 1));
CORRADE_COMPARE(a % b, Vector2i(0, 3));
}
@ -466,14 +484,14 @@ void VectorTest::modulo() {
void VectorTest::bitwise() {
typedef Math::Vector<2, Int> Vector2i;
const Vector2i a(85, 240);
const Vector2i b(170, 85);
CE const Vector2i a(85, 240);
CE const Vector2i b(170, 85);
CORRADE_COMPARE(~a, Vector2i(-86, -241));
CORRADE_COMPARE(a & b, Vector2i(0, 80));
CORRADE_COMPARE(a | b, Vector2i(255, 245));
CORRADE_COMPARE(a ^ b, Vector2i(255, 165));
const Vector2i c(7, 32);
CE const Vector2i c(7, 32);
CORRADE_COMPARE(c << 2, Vector2i(28, 128));
CORRADE_COMPARE(c >> 2, Vector2i(1, 8));
}
@ -487,11 +505,13 @@ void VectorTest::dotSelf() {
}
void VectorTest::length() {
CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).length(), 5.4772256f);
CE const Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CORRADE_COMPARE(a.length(), 5.4772256f);
}
void VectorTest::lengthInverted() {
CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).lengthInverted(), 0.182574f);
CE const Vector4 a(1.0f, 2.0f, 3.0f, 4.0f);
CORRADE_COMPARE(a.lengthInverted(), 0.182574f);
}
void VectorTest::normalized() {
@ -525,7 +545,7 @@ void VectorTest::max() {
}
void VectorTest::minmax() {
const auto expected = std::make_pair(-3.0f, 2.0f);
CE const auto expected = std::make_pair(-3.0f, 2.0f);
CORRADE_COMPARE((Vector3{-1.0f, 2.0f, -3.0f}.minmax()), expected);
CORRADE_COMPARE((Vector3{-1.0f, -3.0f, 2.0f}.minmax()), expected);
CORRADE_COMPARE((Vector3{2.0f, -1.0f, -3.0f}.minmax()), expected);
@ -535,9 +555,9 @@ void VectorTest::minmax() {
}
void VectorTest::nanIgnoring() {
Vector3 oneNan{1.0f, Constants::nan(), -3.0f};
Vector3 firstNan{Constants::nan(), 1.0f, -3.0f};
Vector3 allNan{Constants::nan(), Constants::nan(), Constants::nan()};
CE Vector3 oneNan{1.0f, Constants::nan(), -3.0f};
CE Vector3 firstNan{Constants::nan(), 1.0f, -3.0f};
CE Vector3 allNan{Constants::nan(), Constants::nan(), Constants::nan()};
CORRADE_COMPARE(oneNan.min(), -3.0f);
CORRADE_COMPARE(firstNan.min(), -3.0f);
@ -555,16 +575,16 @@ void VectorTest::nanIgnoring() {
}
void VectorTest::projected() {
Vector3 line(1.0f, -1.0f, 0.5f);
Vector3 projected = Vector3(1.0f, 2.0f, 3.0f).projected(line);
CE Vector3 line(1.0f, -1.0f, 0.5f);
CE Vector3 projected = Vector3(1.0f, 2.0f, 3.0f).projected(line);
CORRADE_COMPARE(projected, Vector3(0.222222f, -0.222222f, 0.111111f));
CORRADE_COMPARE(projected.normalized(), line.normalized());
}
void VectorTest::projectedOntoNormalized() {
Vector3 vector(1.0f, 2.0f, 3.0f);
Vector3 line(1.0f, -1.0f, 0.5f);
CE Vector3 vector(1.0f, 2.0f, 3.0f);
CE Vector3 line(1.0f, -1.0f, 0.5f);
Vector3 projected = vector.projectedOntoNormalized(line.normalized());
CORRADE_COMPARE(projected, Vector3(0.222222f, -0.222222f, 0.111111f));
@ -610,7 +630,7 @@ void VectorTest::angleNormalizedButOver1() {
/* This vector *is* normalized, but its length is larger than 1, which
would cause acos() to return a NaN. Ensure it's clamped to correct range
before passing it there. */
Vector3 a{1.0f + Math::TypeTraits<Float>::epsilon()/2, 0.0f, 0.0f};
CE Vector3 a{1.0f + Math::TypeTraits<Float>::epsilon()/2, 0.0f, 0.0f};
CORRADE_VERIFY(a.isNormalized());
CORRADE_COMPARE(Math::angle(a, a), 0.0_radf);
@ -648,12 +668,12 @@ void VectorTest::subclassTypes() {
CORRADE_VERIFY(std::is_same<decltype(Vec2::from(data)), Vec2&>::value);
CORRADE_VERIFY(std::is_same<decltype(Vec2::from(cdata)), const Vec2&>::value);
Vector<1, Float> one;
CE Vector<1, Float> one;
CORRADE_VERIFY(std::is_same<decltype(Vec2::pad(one)), Vec2>::value);
/* Const operators */
const Vec2 c;
const Vec2 c2;
CE const Vec2 c;
CE const Vec2 c2;
CORRADE_VERIFY(std::is_same<decltype(+c), Vec2>::value);
CORRADE_VERIFY(std::is_same<decltype(-c), Vec2>::value);
CORRADE_VERIFY(std::is_same<decltype(c + c), Vec2>::value);
@ -859,6 +879,11 @@ void VectorTest::debugPacked() {
Debug{&out} << Debug::packed << Vector4(0.5f, 15.0f, 1.0f, 1.0f) << Vector4();
CORRADE_COMPARE(out.str(), "{0.5, 15, 1, 1} Vector(0, 0, 0, 0)\n");
}
#else
void VectorTest::skipTesting() {
CORRADE_SKIP("Relaxed constexpr not supported by the compiler.");
}
#endif
}}}}

25
src/Magnum/Math/TypeTraits.h

@ -392,7 +392,7 @@ Calls @ref TypeTraits<T>::equals() --- using fuzzy compare for floating-point
types and doing equality comparison on integral types. Scalar complement to
@ref equal(const Vector<size, T>& a, const Vector<size, T>&).
*/
template<class T> inline typename std::enable_if<IsScalar<T>::value, bool>::type equal(T a, T b) {
template<class T> constexpr inline typename std::enable_if<IsScalar<T>::value, bool>::type equal(T a, T b) {
return TypeTraits<T>::equals(a, b);
}
@ -404,7 +404,7 @@ Calls @ref TypeTraits<T>::equals() --- using fuzzy compare for floating-point
types and doing equality comparison on integral types. Scalar complement to
@ref notEqual(const Vector<size, T>& a, const Vector<size, T>&).
*/
template<class T> inline typename std::enable_if<IsScalar<T>::value, bool>::type notEqual(T a, T b) {
template<class T> constexpr inline typename std::enable_if<IsScalar<T>::value, bool>::type notEqual(T a, T b) {
return !TypeTraits<T>::equals(a, b);
}
@ -467,17 +467,18 @@ namespace Implementation {
template<class T> struct TypeTraitsFloatingPoint: TypeTraitsName<T> {
TypeTraitsFloatingPoint() = delete;
static bool equals(T a, T b);
static bool equalsZero(T a, T epsilon);
static constexpr inline T abs(T x) { return x < 0 ? -x : x; }
static MAGNUM_CONSTEXPR14 bool equals(T a, T b);
static MAGNUM_CONSTEXPR14 bool equalsZero(T a, T epsilon);
};
template<class T> bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b) {
template<class T> MAGNUM_CONSTEXPR14 bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b) {
/* Shortcut for binary equality (also infinites) */
if(a == b) return true;
const T absA = std::abs(a);
const T absB = std::abs(b);
const T difference = std::abs(a - b);
const T absA = abs(a);
const T absB = abs(b);
const T difference = abs(a - b);
/* One of the numbers is zero or both are extremely close to it, relative
error is meaningless */
@ -488,11 +489,11 @@ template<class T> bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b)
return difference/(absA + absB) < TypeTraits<T>::epsilon();
}
template<class T> bool TypeTraitsFloatingPoint<T>::equalsZero(const T a, const T magnitude) {
template<class T> MAGNUM_CONSTEXPR14 bool TypeTraitsFloatingPoint<T>::equalsZero(const T a, const T magnitude) {
/* Shortcut for binary equality */
if(a == T(0.0)) return true;
const T absA = std::abs(a);
const T absA = abs(a);
/* The value is extremely close to zero, relative error is meaningless */
if(absA < TypeTraits<T>::epsilon())
@ -538,8 +539,8 @@ namespace Implementation {
[1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2,
1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
template<class T> constexpr inline bool isNormalizedSquared(T lengthSquared) {
return TypeTraitsFloatingPoint<T>::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}
}

231
src/Magnum/Math/Vector.h

@ -64,20 +64,21 @@ template<class T> constexpr typename std::enable_if<IsScalar<T>::value, T>::type
namespace Implementation {
template<std::size_t, class, class> struct VectorConverter;
/* Needed by DualQuaternion and Functions.h (to avoid dependency between them) */
template<class T, class U> T lerp(const T& a, const T& b, U t) {
template<class T, class U> constexpr T lerp(const T& a, const T& b, U t) {
return T((U(1) - t)*a + t*b);
}
template<bool integral> struct IsZero;
template<> struct IsZero<false> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
template<typename T> static constexpr T abs(T x) { return x < 0 ? -x : x; }
template<std::size_t size, class T> constexpr bool operator()(const Vector<size, T>& vec) const {
/* Proper comparison should be with epsilon^2, but the value is not
representable in given precision. Comparing to epsilon instead. */
return std::abs(vec.dot()) < TypeTraits<T>::epsilon();
return abs(vec.dot()) < TypeTraits<T>::epsilon();
}
};
template<> struct IsZero<true> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
template<std::size_t size, class T> constexpr bool operator()(const Vector<size, T>& vec) const {
return vec == Vector<size, T>{};
}
};
@ -101,7 +102,7 @@ the same general direction, `1` when two *normalized* vectors are parallel,
@f]
@see @ref Vector::dot() const, @ref Vector::operator-(), @ref Vector2::perpendicular()
*/
template<std::size_t size, class T> inline T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
T out{};
for(std::size_t i = 0; i != size; ++i)
out += a._data[i]*b._data[i];
@ -245,7 +246,7 @@ template<std::size_t size, class T> class Vector {
T* data();
constexpr const T* data() const; /**< @overload */
#else
auto data() -> T(&)[size] { return _data; }
MAGNUM_CONSTEXPR14 auto data() -> T(&)[size] { return _data; }
constexpr auto data() const -> const T(&)[size] { return _data; }
#endif
@ -254,7 +255,7 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref data()
*/
T& operator[](std::size_t pos) { return _data[pos]; }
MAGNUM_CONSTEXPR14 T& operator[](std::size_t pos) { return _data[pos]; }
constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */
/**
@ -262,7 +263,7 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref Math::equal()
*/
bool operator==(const Vector<size, T>& other) const {
MAGNUM_CONSTEXPR14 bool operator==(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if(!TypeTraits<T>::equals(_data[i], other._data[i])) return false;
@ -336,7 +337,7 @@ template<std::size_t size, class T> class Vector {
*
* Returns the value as-is.
*/
Vector<size, T> operator+() const { return *this; }
MAGNUM_CONSTEXPR14 Vector<size, T> operator+() const { return *this; }
/**
* @brief Negated vector
@ -349,7 +350,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif
operator-() const;
@ -360,7 +361,7 @@ template<std::size_t size, class T> class Vector {
* \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i
* @f]
*/
Vector<size, T>& operator+=(const Vector<size, T>& other) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator+=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] += other._data[i];
@ -372,7 +373,7 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref operator+=(), @ref sum()
*/
Vector<size, T> operator+(const Vector<size, T>& other) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this) += other;
}
@ -383,7 +384,7 @@ template<std::size_t size, class T> class Vector {
* \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i
* @f]
*/
Vector<size, T>& operator-=(const Vector<size, T>& other) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator-=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] -= other._data[i];
@ -395,7 +396,7 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref operator-=()
*/
Vector<size, T> operator-(const Vector<size, T>& other) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this) -= other;
}
@ -408,7 +409,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator*=(const Vector<size, T>&),
* @ref operator*=(Vector<size, Integral>&, FloatingPoint)
*/
Vector<size, T>& operator*=(T scalar) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator*=(T scalar) {
for(std::size_t i = 0; i != size; ++i)
_data[i] *= scalar;
@ -422,7 +423,7 @@ template<std::size_t size, class T> class Vector {
* @ref operator*=(T), @ref operator*(T, const Vector<size, T>&),
* @ref operator*(const Vector<size, Integral>&, FloatingPoint)
*/
Vector<size, T> operator*(T scalar) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator*(T scalar) const {
return Vector<size, T>(*this) *= scalar;
}
@ -435,7 +436,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator/=(const Vector<size, T>&),
* @ref operator/=(Vector<size, Integral>&, FloatingPoint)
*/
Vector<size, T>& operator/=(T scalar) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator/=(T scalar) {
for(std::size_t i = 0; i != size; ++i)
_data[i] /= scalar;
@ -449,7 +450,7 @@ template<std::size_t size, class T> class Vector {
* @ref operator/=(T), @ref operator/(T, const Vector<size, T>&),
* @ref operator/(const Vector<size, Integral>&, FloatingPoint)
*/
Vector<size, T> operator/(T scalar) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator/(T scalar) const {
return Vector<size, T>(*this) /= scalar;
}
@ -462,7 +463,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator*=(T),
* @ref operator*=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/
Vector<size, T>& operator*=(const Vector<size, T>& other) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator*=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] *= other._data[i];
@ -476,7 +477,7 @@ template<std::size_t size, class T> class Vector {
* @ref operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&),
* @ref product()
*/
Vector<size, T> operator*(const Vector<size, T>& other) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator*(const Vector<size, T>& other) const {
return Vector<size, T>(*this) *= other;
}
@ -489,7 +490,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator/=(T),
* @ref operator/=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/
Vector<size, T>& operator/=(const Vector<size, T>& other) {
MAGNUM_CONSTEXPR14 Vector<size, T>& operator/=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] /= other._data[i];
@ -502,7 +503,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator/(T) const, @ref operator/=(const Vector<size, T>&),
* @ref operator/(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/
Vector<size, T> operator/(const Vector<size, T>& other) const {
MAGNUM_CONSTEXPR14 Vector<size, T> operator/(const Vector<size, T>& other) const {
return Vector<size, T>(*this) /= other;
}
@ -517,7 +518,7 @@ template<std::size_t size, class T> class Vector {
* @ref isNormalized(), @ref Distance::pointPointSquared(),
* @ref Intersection::pointSphere()
*/
T dot() const { return Math::dot(*this, *this); }
MAGNUM_CONSTEXPR14 T dot() const { return Math::dot(*this, *this); }
/**
* @brief Vector length
@ -544,7 +545,7 @@ template<std::size_t size, class T> class Vector {
* @ref Intersection::pointSphere()
* @todo something like std::hypot() for possibly better precision?
*/
T length() const { return T(std::sqrt(dot())); }
MAGNUM_CONSTEXPR14 T length() const { return T(std::sqrt(dot())); }
/**
* @brief Inverse vector length
@ -558,7 +559,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_floating_point<U>::value, T>::type
#endif
lengthInverted() const { return T(1)/length(); }
@ -572,7 +573,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
normalized() const { return *this*lengthInverted(); }
@ -590,7 +591,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
resized(T length) const {
return *this*(lengthInverted()*length);
@ -608,7 +609,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
projected(const Vector<size, T>& line) const {
return line*Math::dot(*this, line)/line.dot();
@ -627,7 +628,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
template<class U = T> MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
projectedOntoNormalized(const Vector<size, T>& line) const;
@ -647,14 +648,14 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref operator+(), @ref length()
*/
T sum() const;
MAGNUM_CONSTEXPR14 T sum() const;
/**
* @brief Product of values in the vector
*
* @see @ref operator*(const Vector<size, T>&) const
*/
T product() const;
MAGNUM_CONSTEXPR14 T product() const;
/**
* @brief Minimal value in the vector
@ -662,7 +663,7 @@ template<std::size_t size, class T> class Vector {
* <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref Math::min(), @ref minmax(), @ref Math::isNan()
*/
T min() const;
MAGNUM_CONSTEXPR14 T min() const;
/**
* @brief Maximal value in the vector
@ -670,7 +671,7 @@ template<std::size_t size, class T> class Vector {
* <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref Math::max(), @ref minmax(), @ref Math::isNan()
*/
T max() const;
MAGNUM_CONSTEXPR14 T max() const;
/**
* @brief Minimal and maximal value in the vector
@ -678,7 +679,7 @@ template<std::size_t size, class T> class Vector {
* <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref min(), @ref max(), @ref Math::minmax(), @ref Math::isNan()
*/
std::pair<T, T> minmax() const;
MAGNUM_CONSTEXPR14 std::pair<T, T> minmax() const;
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
@ -710,7 +711,7 @@ template<std::size_t size, class T> class Vector {
template<std::size_t size_, class T_> friend BitVector<size_> equal(const Vector<size_, T_>&, const Vector<size_, T_>&);
template<std::size_t size_, class T_> friend BitVector<size_> notEqual(const Vector<size_, T_>&, const Vector<size_, T_>&);
template<std::size_t size_, class U> friend U dot(const Vector<size_, U>&, const Vector<size_, U>&);
template<std::size_t size_, class U> friend MAGNUM_CONSTEXPR14 U dot(const Vector<size_, U>&, const Vector<size_, U>&);
/* Implementation for Vector<size, T>::Vector(const Vector<size, U>&) */
template<class U, std::size_t ...sequence> constexpr explicit Vector(Corrade::Containers::Implementation::Sequence<sequence...>, const Vector<size, U>& vector) noexcept: _data{T(vector._data[sequence])...} {}
@ -764,7 +765,7 @@ template<std::size_t size, class T> inline BitVector<size> notEqual(const Vector
Same as @ref Vector::operator*(T) const.
*/
template<std::size_t size, class T> inline Vector<size, T> operator*(
template<std::size_t size, class T> inline Vector<size, T> MAGNUM_CONSTEXPR14 operator*(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
@ -783,7 +784,7 @@ template<std::size_t size, class T> inline Vector<size, T> operator*(
@f]
@see @ref Vector::operator/(T) const
*/
template<std::size_t size, class T> inline Vector<size, T> operator/(
template<std::size_t size, class T> inline Vector<size, T> MAGNUM_CONSTEXPR14 operator/(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
@ -804,7 +805,7 @@ template<std::size_t size, class T> inline Vector<size, T> operator/(
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -820,7 +821,7 @@ operator%=(Vector<size, Integral>& a, Integral b) {
/** @relates Vector
@brief Modulo of an integral vector
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -836,7 +837,7 @@ operator%(const Vector<size, Integral>& a, Integral b) {
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -852,7 +853,7 @@ operator%=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector
@brief Modulo of two integral vectors
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -866,7 +867,7 @@ operator%(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector
@brief Bitwise NOT of an integral vector
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -886,7 +887,7 @@ operator~(const Vector<size, Integral>& vector) {
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -902,7 +903,7 @@ operator&=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector
@brief Bitwise AND of two integral vectors
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -918,7 +919,7 @@ operator&(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -934,7 +935,7 @@ operator|=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector
@brief Bitwise OR of two integral vectors
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -950,7 +951,7 @@ operator|(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -966,7 +967,7 @@ operator^=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector
@brief Bitwise XOR of two integral vectors
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -982,7 +983,7 @@ operator^(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1005,7 +1006,7 @@ operator<<=(Vector<size, Integral>& vector,
/** @relates Vector
@brief Bitwise left shift of an integral vector
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1028,7 +1029,7 @@ operator<<(const Vector<size, Integral>& vector,
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1050,7 +1051,7 @@ operator>>=(Vector<size, Integral>& vector,
/** @relates Vector
@brief Bitwise left shift of an integral vector
*/
template<std::size_t size, class Integral> inline
template<std::size_t size, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1073,7 +1074,7 @@ operator>>(const Vector<size, Integral>& vector,
Similar to @ref Vector::operator*=(T), except that the multiplication is done
in floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1092,7 +1093,7 @@ operator*=(Vector<size, Integral>& vector, FloatingPoint scalar) {
Similar to @ref Vector::operator*(T) const, except that the multiplication is
done in floating-point.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1108,7 +1109,7 @@ operator*(const Vector<size, Integral>& vector, FloatingPoint scalar) {
Same as @ref operator*(const Vector<size, Integral>&, FloatingPoint).
*/
template<std::size_t size, class FloatingPoint, class Integral> inline
template<std::size_t size, class FloatingPoint, class Integral> constexpr inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1124,7 +1125,7 @@ operator*(FloatingPoint scalar, const Vector<size, Integral>& vector) {
Similar to @ref Vector::operator/=(T), except that the division is done in
floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1143,7 +1144,7 @@ operator/=(Vector<size, Integral>& vector, FloatingPoint scalar) {
Similar to @ref Vector::operator/(T) const, except that the division is done in
floating-point.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1160,7 +1161,7 @@ operator/(const Vector<size, Integral>& vector, FloatingPoint scalar) {
Similar to @ref Vector::operator*=(const Vector<size, T>&), except that the
multiplication is done in floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1181,7 +1182,7 @@ the multiplication is done in floating-point. The result is always integral
vector, convert both arguments to the same floating-point type to have
floating-point result.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1197,7 +1198,7 @@ operator*(const Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b)
Same as @ref operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&).
*/
template<std::size_t size, class FloatingPoint, class Integral> inline
template<std::size_t size, class FloatingPoint, class Integral> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1213,7 +1214,7 @@ operator*(const Vector<size, FloatingPoint>& a, const Vector<size, Integral>& b)
Similar to @ref Vector::operator/=(const Vector<size, T>&), except that the
division is done in floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
@ -1234,7 +1235,7 @@ the division is done in floating-point. The result is always integral vector,
convert both arguments to the same floating-point type to have floating-point
result.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
template<std::size_t size, class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
@ -1288,66 +1289,66 @@ extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utili
return Math::Vector<size, T>::pad(a, value); \
} \
\
Type<T> operator+() const { \
constexpr Type<T> operator+() const { \
return Math::Vector<size, T>::operator+(); \
} \
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Type<T>>::type \
operator-() const { \
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Type<T>>::type \
constexpr operator-() const { \
return Math::Vector<size, T>::operator-(); \
} \
Type<T>& operator+=(const Math::Vector<size, T>& other) { \
MAGNUM_CONSTEXPR14 Type<T>& operator+=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator+=(other); \
return *this; \
} \
Type<T> operator+(const Math::Vector<size, T>& other) const { \
constexpr Type<T> operator+(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator+(other); \
} \
Type<T>& operator-=(const Math::Vector<size, T>& other) { \
MAGNUM_CONSTEXPR14 Type<T>& operator-=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator-=(other); \
return *this; \
} \
Type<T> operator-(const Math::Vector<size, T>& other) const { \
MAGNUM_CONSTEXPR14 Type<T> operator-(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator-(other); \
} \
Type<T>& operator*=(T number) { \
MAGNUM_CONSTEXPR14 Type<T>& operator*=(T number) { \
Math::Vector<size, T>::operator*=(number); \
return *this; \
} \
Type<T> operator*(T number) const { \
constexpr Type<T> operator*(T number) const { \
return Math::Vector<size, T>::operator*(number); \
} \
Type<T>& operator/=(T number) { \
MAGNUM_CONSTEXPR14 Type<T>& operator/=(T number) { \
Math::Vector<size, T>::operator/=(number); \
return *this; \
} \
Type<T> operator/(T number) const { \
constexpr Type<T> operator/(T number) const { \
return Math::Vector<size, T>::operator/(number); \
} \
Type<T>& operator*=(const Math::Vector<size, T>& other) { \
MAGNUM_CONSTEXPR14 Type<T>& operator*=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator*=(other); \
return *this; \
} \
Type<T> operator*(const Math::Vector<size, T>& other) const { \
MAGNUM_CONSTEXPR14 Type<T> operator*(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \
} \
Type<T>& operator/=(const Math::Vector<size, T>& other) { \
MAGNUM_CONSTEXPR14 Type<T>& operator/=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator/=(other); \
return *this; \
} \
Type<T> operator/(const Math::Vector<size, T>& other) const { \
constexpr Type<T> operator/(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator/(other); \
} \
\
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type normalized() const { \
template<class U = T> constexpr typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type normalized() const { \
return Math::Vector<size, T>::normalized(); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type resized(T length) const { \
template<class U = T> constexpr typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type resized(T length) const { \
return Math::Vector<size, T>::resized(length); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projected(const Math::Vector<size, T>& other) const { \
template<class U = T> constexpr typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projected(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projected(other); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
template<class U = T> constexpr typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projectedOntoNormalized(other); \
} \
constexpr Type<T> flipped() const { \
@ -1355,99 +1356,99 @@ extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utili
}
#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class T> inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& vector) { \
template<class T> constexpr inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number*static_cast<const Math::Vector<size, T>&>(vector); \
} \
template<class T> inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& vector) { \
template<class T> constexpr inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number/static_cast<const Math::Vector<size, T>&>(vector); \
} \
\
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, Integral b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, Integral b) { \
static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, Integral b) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, Integral b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) % b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) % b; \
} \
\
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator~(const Type<Integral>& vector) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator~(const Type<Integral>& vector) { \
return ~static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator&=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator&=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) &= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator&(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator&(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) & b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator|=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator|=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) |= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator|(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator|(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) | b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator^=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator^=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) ^= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator^(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator^(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) ^ b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator<<=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator<<=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) <<= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator<<(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
template<class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator<<(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) << shift; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator>>=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator>>=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) >>= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator>>(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
template<class Integral> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator>>(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) >> shift; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& vector, FloatingPoint number) { \
template<class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) *= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& vector, FloatingPoint number) { \
template<class Integral, class FloatingPoint> constexpr inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)*number; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint number, const Type<Integral>& vector) { \
template<class FloatingPoint, class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint number, const Type<Integral>& vector) { \
return number*static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& vector, FloatingPoint number) { \
template<class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) /= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& vector, FloatingPoint number) { \
template<class Integral, class FloatingPoint> constexpr inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)/number; \
} \
\
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
template<class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) *= b; \
return a; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
template<class Integral, class FloatingPoint> constexpr inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a)*b; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Math::Vector<size, FloatingPoint>& a, const Type<Integral>& b) { \
template<class FloatingPoint, class Integral> constexpr inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Math::Vector<size, FloatingPoint>& a, const Type<Integral>& b) { \
return a*static_cast<const Math::Vector<size, Integral>&>(b); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
template<class Integral, class FloatingPoint> inline MAGNUM_CONSTEXPR14 typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) /= b; \
return a; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
template<class Integral, class FloatingPoint> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a)/b; \
}
#endif
@ -1494,7 +1495,7 @@ inline Vector<size, T>
#else
template<class U> inline typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif
Vector<size, T>::operator-() const {
MAGNUM_CONSTEXPR14 Vector<size, T>::operator-() const {
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
@ -1507,7 +1508,7 @@ template<std::size_t size, class T>
#ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T>
#else
template<class U> inline typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
template<class U> MAGNUM_CONSTEXPR14 inline typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(),
@ -1515,7 +1516,7 @@ Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
return line*Math::dot(*this, line);
}
template<std::size_t size, class T> inline T Vector<size, T>::sum() const {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline T Vector<size, T>::sum() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
@ -1524,7 +1525,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::sum() const {
return out;
}
template<std::size_t size, class T> inline T Vector<size, T>::product() const {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline T Vector<size, T>::product() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
@ -1549,7 +1550,7 @@ namespace Implementation {
}
}
template<std::size_t size, class T> inline T Vector<size, T>::min() const {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline T Vector<size, T>::min() const {
std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T out(_data[i]);
@ -1559,7 +1560,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::min() const {
return out;
}
template<std::size_t size, class T> inline T Vector<size, T>::max() const {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline T Vector<size, T>::max() const {
std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T out(_data[i]);
@ -1569,7 +1570,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::max() const {
return out;
}
template<std::size_t size, class T> inline std::pair<T, T> Vector<size, T>::minmax() const {
template<std::size_t size, class T> MAGNUM_CONSTEXPR14 inline std::pair<T, T> Vector<size, T>::minmax() const {
std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T min{_data[i]}, max{_data[i]};

12
src/Magnum/Math/Vector2.h

@ -51,7 +51,7 @@ for more information.
@see @ref Vector2::perpendicular(),
@ref dot(const Vector<size, T>&, const Vector<size, T>&)
*/
template<class T> inline T cross(const Vector2<T>& a, const Vector2<T>& b) {
template<class T> constexpr inline T cross(const Vector2<T>& a, const Vector2<T>& b) {
return a._data[0]*b._data[1] - a._data[1]*b._data[0];
}
@ -146,9 +146,9 @@ template<class T> class Vector2: public Vector<2, T> {
/** @brief Copy constructor */
constexpr /*implicit*/ Vector2(const Vector<2, T>& other) noexcept: Vector<2, T>(other) {}
T& x() { return Vector<2, T>::_data[0]; } /**< @brief X component */
MAGNUM_CONSTEXPR14 T& x() { return Vector<2, T>::_data[0]; } /**< @brief X component */
constexpr T x() const { return Vector<2, T>::_data[0]; } /**< @overload */
T& y() { return Vector<2, T>::_data[1]; } /**< @brief Y component */
MAGNUM_CONSTEXPR14 T& y() { return Vector<2, T>::_data[1]; } /**< @brief Y component */
constexpr T y() const { return Vector<2, T>::_data[1]; } /**< @overload */
/**
@ -166,7 +166,7 @@ template<class T> class Vector2: public Vector<2, T> {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector2<T>
#else
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Vector2<T>>::type
template<class U = T> constexpr typename std::enable_if<std::is_signed<U>::value, Vector2<T>>::type
#endif
perpendicular() const { return {-y(), x()}; }
@ -181,14 +181,14 @@ template<class T> class Vector2: public Vector<2, T> {
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
template<class U = T> constexpr typename std::enable_if<std::is_floating_point<U>::value, T>::type
#endif
aspectRatio() const { return x()/y(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2)
private:
template<class U> friend U cross(const Vector2<U>&, const Vector2<U>&);
template<class U> friend constexpr U cross(const Vector2<U>&, const Vector2<U>&);
};
#ifndef DOXYGEN_GENERATING_OUTPUT

18
src/Magnum/Math/Vector3.h

@ -50,7 +50,7 @@ distance of a point and a line, see @ref Distance::linePoint(const Vector3<T>&,
for more information.
@see @ref cross(const Vector2<T>&, const Vector2<T>&), @ref planeEquation()
*/
template<class T> inline Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
template<class T> constexpr inline Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
return {
a._data[1]*b._data[2] - b._data[1]*a._data[2],
a._data[2]*b._data[0] - b._data[2]*a._data[0],
@ -180,7 +180,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* @see @ref r()
*/
T& x() { return Vector<3, T>::_data[0]; }
MAGNUM_CONSTEXPR14 T& x() { return Vector<3, T>::_data[0]; }
constexpr T x() const { return Vector<3, T>::_data[0]; } /**< @overload */
/**
@ -188,7 +188,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* @see @ref g()
*/
T& y() { return Vector<3, T>::_data[1]; }
MAGNUM_CONSTEXPR14 T& y() { return Vector<3, T>::_data[1]; }
constexpr T y() const { return Vector<3, T>::_data[1]; } /**< @overload */
/**
@ -196,7 +196,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* @see @ref b()
*/
T& z() { return Vector<3, T>::_data[2]; }
MAGNUM_CONSTEXPR14 T& z() { return Vector<3, T>::_data[2]; }
constexpr T z() const { return Vector<3, T>::_data[2]; } /**< @overload */
/**
@ -204,7 +204,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* Equivalent to @ref x().
*/
T& r() { return Vector<3, T>::_data[0]; }
MAGNUM_CONSTEXPR14 T& r() { return Vector<3, T>::_data[0]; }
constexpr T r() const { return Vector<3, T>::_data[0]; } /**< @overload */
/**
@ -212,7 +212,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* Equivalent to @ref y().
*/
T& g() { return Vector<3, T>::_data[1]; }
MAGNUM_CONSTEXPR14 T& g() { return Vector<3, T>::_data[1]; }
constexpr T g() const { return Vector<3, T>::_data[1]; } /**< @overload */
/**
@ -220,7 +220,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* Equivalent to @ref z().
*/
T& b() { return Vector<3, T>::_data[2]; }
MAGNUM_CONSTEXPR14 T& b() { return Vector<3, T>::_data[2]; }
constexpr T b() const { return Vector<3, T>::_data[2]; } /**< @overload */
/**
@ -229,7 +229,7 @@ template<class T> class Vector3: public Vector<3, T> {
*
* @see @ref gather(), @ref scatter()
*/
Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
MAGNUM_CONSTEXPR14 Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
constexpr const Vector2<T> xy() const {
return {Vector<3, T>::_data[0], Vector<3, T>::_data[1]};
} /**< @overload */
@ -237,7 +237,7 @@ template<class T> class Vector3: public Vector<3, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Vector3)
private:
template<class U> friend Vector3<U> cross(const Vector3<U>&, const Vector3<U>&);
template<class U> friend constexpr Vector3<U> cross(const Vector3<U>&, const Vector3<U>&);
};
#ifndef DOXYGEN_GENERATING_OUTPUT

26
src/Magnum/Math/Vector4.h

@ -120,7 +120,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref r()
*/
T& x() { return Vector<4, T>::_data[0]; }
MAGNUM_CONSTEXPR14 T& x() { return Vector<4, T>::_data[0]; }
constexpr T x() const { return Vector<4, T>::_data[0]; } /**< @overload */
/**
@ -128,7 +128,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref g()
*/
T& y() { return Vector<4, T>::_data[1]; }
MAGNUM_CONSTEXPR14 T& y() { return Vector<4, T>::_data[1]; }
constexpr T y() const { return Vector<4, T>::_data[1]; } /**< @overload */
/**
@ -136,7 +136,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref b()
*/
T& z() { return Vector<4, T>::_data[2]; }
MAGNUM_CONSTEXPR14 T& z() { return Vector<4, T>::_data[2]; }
constexpr T z() const { return Vector<4, T>::_data[2]; } /**< @overload */
/**
@ -144,7 +144,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref a()
*/
T& w() { return Vector<4, T>::_data[3]; }
MAGNUM_CONSTEXPR14 T& w() { return Vector<4, T>::_data[3]; }
constexpr T w() const { return Vector<4, T>::_data[3]; } /**< @overload */
/**
@ -152,7 +152,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* Equivalent to @ref x().
*/
T& r() { return Vector<4, T>::_data[0]; }
MAGNUM_CONSTEXPR14 T& r() { return Vector<4, T>::_data[0]; }
constexpr T r() const { return Vector<4, T>::_data[0]; } /**< @overload */
/**
@ -160,7 +160,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* Equivalent to @ref y().
*/
T& g() { return Vector<4, T>::_data[1]; }
MAGNUM_CONSTEXPR14 T& g() { return Vector<4, T>::_data[1]; }
constexpr T g() const { return Vector<4, T>::_data[1]; } /**< @overload */
/**
@ -168,7 +168,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* Equivalent to @ref z().
*/
T& b() { return Vector<4, T>::_data[2]; }
MAGNUM_CONSTEXPR14 T& b() { return Vector<4, T>::_data[2]; }
constexpr T b() const { return Vector<4, T>::_data[2]; } /**< @overload */
/**
@ -176,7 +176,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* Equivalent to @ref w().
*/
T& a() { return Vector<4, T>::_data[3]; }
MAGNUM_CONSTEXPR14 T& a() { return Vector<4, T>::_data[3]; }
constexpr T a() const { return Vector<4, T>::_data[3]; } /**< @overload */
/**
@ -185,7 +185,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref rgb(), @ref gather(), @ref scatter()
*/
Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
MAGNUM_CONSTEXPR14 Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
constexpr const Vector3<T> xyz() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
} /**< @overload */
@ -197,7 +197,7 @@ template<class T> class Vector4: public Vector<4, T> {
* Equivalent to @ref xyz().
* @see @ref gather(), @ref scatter()
*/
Vector3<T>& rgb() { return Vector3<T>::from(Vector<4, T>::data()); }
MAGNUM_CONSTEXPR14 Vector3<T>& rgb() { return Vector3<T>::from(Vector<4, T>::data()); }
constexpr const Vector3<T> rgb() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
} /**< @overload */
@ -208,7 +208,7 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see @ref gather(), @ref scatter()
*/
Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
MAGNUM_CONSTEXPR14 Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
constexpr const Vector2<T> xy() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1]};
} /**< @overload */
@ -237,7 +237,7 @@ when assigning @f$ \boldsymbol{p_i} @f$ to @f$ x @f$, @f$ y @f$, @f$ z @f$. @f[
@see @ref planeEquation(const Vector3<T>&, const Vector3<T>&), @ref cross(),
@ref dot()
*/
template<class T> Vector4<T> planeEquation(const Vector3<T>& p0, const Vector3<T>& p1, const Vector3<T>& p2) {
template<class T> MAGNUM_CONSTEXPR14 Vector4<T> planeEquation(const Vector3<T>& p0, const Vector3<T>& p1, const Vector3<T>& p2) {
const Vector3<T> normal = Math::cross(p1 - p0, p2 - p0).normalized();
return {normal, -Math::dot(normal, p0)};
}
@ -260,7 +260,7 @@ using a dot product with the normal @f$ \boldsymbol{n} @f$ using the point
@see @ref planeEquation(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&),
@ref dot(), @ref Frustum
*/
template<class T> Vector4<T> planeEquation(const Vector3<T>& normal, const Vector3<T>& point) {
template<class T> MAGNUM_CONSTEXPR14 Vector4<T> planeEquation(const Vector3<T>& normal, const Vector3<T>& point) {
return {normal, -Math::dot(normal, point)};
}

Loading…
Cancel
Save