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 #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(MathVector2Test Vector2Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector4Test Vector4Test.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(MathColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathRectangularMatrixTest RectangularMatrixTest.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/StrictWeakOrdering.h"
#include "Magnum/Math/Swizzle.h" #include "Magnum/Math/Swizzle.h"
#include "Cpp14VectorTest.h"
struct Vec2 { struct Vec2 {
float x, y; float x, y;
}; };
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector2Test: Corrade::TestSuite::Tester { struct Vector2Test: Corrade::TestSuite::Tester {
explicit Vector2Test(); explicit Vector2Test();
#ifndef SKIP_TESTING
void construct(); void construct();
void constructDefault(); void constructDefault();
void constructNoInit(); void constructNoInit();
@ -76,6 +79,9 @@ struct Vector2Test: Corrade::TestSuite::Tester {
void swizzleType(); void swizzleType();
void debug(); void debug();
#else
void skipTesting();
#endif
}; };
typedef Math::Vector3<Int> Vector3i; typedef Math::Vector3<Int> Vector3i;
@ -83,7 +89,14 @@ typedef Math::Vector2<Float> Vector2;
typedef Math::Vector2<Int> Vector2i; typedef Math::Vector2<Int> Vector2i;
Vector2Test::Vector2Test() { Vector2Test::Vector2Test() {
addTests({&Vector2Test::construct, #ifndef TESTING_CONSTEXPR
setTestName("MathVector2Test");
#else
setTestName("Cpp14MathVector2Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector2Test::construct,
&Vector2Test::constructDefault, &Vector2Test::constructDefault,
&Vector2Test::constructNoInit, &Vector2Test::constructNoInit,
&Vector2Test::constructOneValue, &Vector2Test::constructOneValue,
@ -101,9 +114,15 @@ Vector2Test::Vector2Test() {
&Vector2Test::strictWeakOrdering, &Vector2Test::strictWeakOrdering,
&Vector2Test::swizzleType, &Vector2Test::swizzleType,
&Vector2Test::debug}); &Vector2Test::debug
#else
&Vector2Test::skipTesting
#endif
});
} }
#ifndef SKIP_TESTING
void Vector2Test::construct() { void Vector2Test::construct() {
constexpr Vector2 a = {1.5f, 2.5f}; constexpr Vector2 a = {1.5f, 2.5f};
CORRADE_COMPARE(a, (Vector<2, Float>(1.5f, 2.5f))); CORRADE_COMPARE(a, (Vector<2, Float>(1.5f, 2.5f)));
@ -197,7 +216,7 @@ void Vector2Test::convert() {
} }
void Vector2Test::access() { 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.x(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f); CORRADE_COMPARE(vec.y(), -2.0f);
@ -209,8 +228,8 @@ void Vector2Test::access() {
} }
void Vector2Test::cross() { void Vector2Test::cross() {
Vector2i a(1, -1); CE Vector2i a(1, -1);
Vector2i b(4, 3); CE Vector2i b(4, 3);
CORRADE_COMPARE(Math::cross(a, b), 7); CORRADE_COMPARE(Math::cross(a, b), 7);
CORRADE_COMPARE(Math::cross<Int>({a, 0}, {b, 0}), Vector3i(0, 0, Math::cross(a, b))); 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); Debug(&o) << Vector2(0.5f, 15.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15)\n"); 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. DEALINGS IN THE SOFTWARE.
*/ */
#include "Cpp14VectorTest.h"
#include <sstream> #include <sstream>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector3Test: Corrade::TestSuite::Tester { struct Vector3Test: Corrade::TestSuite::Tester {
explicit Vector3Test(); explicit Vector3Test();
#ifndef SKIP_TESTING
void construct(); void construct();
void constructDefault(); void constructDefault();
void constructNoInit(); void constructNoInit();
@ -76,6 +79,9 @@ struct Vector3Test: Corrade::TestSuite::Tester {
void swizzleType(); void swizzleType();
void debug(); void debug();
#else
void skipTesting();
#endif
}; };
typedef Math::Vector3<Float> Vector3; typedef Math::Vector3<Float> Vector3;
@ -83,7 +89,14 @@ typedef Math::Vector3<Int> Vector3i;
typedef Math::Vector2<Float> Vector2; typedef Math::Vector2<Float> Vector2;
Vector3Test::Vector3Test() { Vector3Test::Vector3Test() {
addTests({&Vector3Test::construct, #ifndef TESTING_CONSTEXPR
setTestName("MathVector3Test");
#else
setTestName("Cpp14MathVector3Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector3Test::construct,
&Vector3Test::constructDefault, &Vector3Test::constructDefault,
&Vector3Test::constructNoInit, &Vector3Test::constructNoInit,
&Vector3Test::constructOneValue, &Vector3Test::constructOneValue,
@ -101,9 +114,13 @@ Vector3Test::Vector3Test() {
&Vector3Test::strictWeakOrdering, &Vector3Test::strictWeakOrdering,
&Vector3Test::swizzleType, &Vector3Test::swizzleType,
&Vector3Test::debug}); &Vector3Test::debug
#else
&Vector3Test::skipTesting
#endif
});
} }
#ifndef SKIP_TESTING
void Vector3Test::construct() { void Vector3Test::construct() {
constexpr Vector3 a = {1.0f, 2.5f, -3.0f}; constexpr Vector3 a = {1.0f, 2.5f, -3.0f};
CORRADE_COMPARE(a, (Vector<3, Float>(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() { 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.x(), 1.0f);
CORRADE_COMPARE(vec.r(), 1.0f); CORRADE_COMPARE(vec.r(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f); CORRADE_COMPARE(vec.y(), -2.0f);
@ -230,8 +247,8 @@ void Vector3Test::access() {
} }
void Vector3Test::cross() { void Vector3Test::cross() {
Vector3i a(1, -1, 1); CE Vector3i a(1, -1, 1);
Vector3i b(4, 3, 7); CE Vector3i b(4, 3, 7);
CORRADE_COMPARE(Math::cross(a, b), Vector3i(-10, -3, 7)); CORRADE_COMPARE(Math::cross(a, b), Vector3i(-10, -3, 7));
} }
@ -255,7 +272,7 @@ void Vector3Test::scales() {
} }
void Vector3Test::twoComponent() { 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)); CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f));
constexpr Vector3 b(1.0f, 2.0f, 3.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); Debug(&o) << Vector3(0.5f, 15.0f, 1.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1)\n"); 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) 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/StrictWeakOrdering.h"
#include "Magnum/Math/Swizzle.h" #include "Magnum/Math/Swizzle.h"
#include "Cpp14VectorTest.h"
struct Vec4 { struct Vec4 {
float x, y, z, w; float x, y, z, w;
}; };
@ -57,6 +59,7 @@ namespace Test { namespace {
struct Vector4Test: Corrade::TestSuite::Tester { struct Vector4Test: Corrade::TestSuite::Tester {
explicit Vector4Test(); explicit Vector4Test();
#ifndef SKIP_TESTING
void construct(); void construct();
void constructPad(); void constructPad();
void constructDefault(); void constructDefault();
@ -78,6 +81,9 @@ struct Vector4Test: Corrade::TestSuite::Tester {
void swizzleType(); void swizzleType();
void debug(); void debug();
#else
void skipTesting();
#endif
}; };
typedef Math::Vector4<Float> Vector4; typedef Math::Vector4<Float> Vector4;
@ -86,7 +92,14 @@ typedef Math::Vector3<Float> Vector3;
typedef Math::Vector2<Float> Vector2; typedef Math::Vector2<Float> Vector2;
Vector4Test::Vector4Test() { Vector4Test::Vector4Test() {
addTests({&Vector4Test::construct, #ifndef TESTING_CONSTEXPR
setTestName("MathVector4Test");
#else
setTestName("Cpp14MathVector4Test");
#endif
addTests({
#ifndef SKIP_TESTING
&Vector4Test::construct,
&Vector4Test::constructPad, &Vector4Test::constructPad,
&Vector4Test::constructDefault, &Vector4Test::constructDefault,
&Vector4Test::constructNoInit, &Vector4Test::constructNoInit,
@ -106,9 +119,14 @@ Vector4Test::Vector4Test() {
&Vector4Test::strictWeakOrdering, &Vector4Test::strictWeakOrdering,
&Vector4Test::swizzleType, &Vector4Test::swizzleType,
&Vector4Test::debug}); &Vector4Test::debug
#else
&Vector4Test::skipTesting
#endif
});
} }
#ifndef SKIP_TESTING
void Vector4Test::construct() { void Vector4Test::construct() {
constexpr Vector4 a = {1.0f, -2.5f, 3.0f, 4.1f}; 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))); CORRADE_COMPARE(a, (Vector<4, Float>(1.0f, -2.5f, 3.0f, 4.1f)));
@ -228,7 +246,7 @@ void Vector4Test::convert() {
} }
void Vector4Test::access() { 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.x(), 1.0f);
CORRADE_COMPARE(vec.r(), 1.0f); CORRADE_COMPARE(vec.r(), 1.0f);
CORRADE_COMPARE(vec.y(), -2.0f); CORRADE_COMPARE(vec.y(), -2.0f);
@ -258,7 +276,7 @@ void Vector4Test::access() {
} }
void Vector4Test::threeComponent() { 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.xyz(), Vector3(1.0f, 2.0f, 3.0f));
CORRADE_COMPARE(a.rgb(), 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() { 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)); CORRADE_COMPARE(a.xy(), Vector2(1.0f, 2.0f));
constexpr Vector4 b(1.0f, 2.0f, 3.0f, 4.0f); constexpr Vector4 b(1.0f, 2.0f, 3.0f, 4.0f);
@ -281,9 +299,9 @@ void Vector4Test::twoComponent() {
} }
void Vector4Test::planeEquationThreePoints() { void Vector4Test::planeEquationThreePoints() {
const Vector3 a{1.0f, 0.5f, 3.0f}; CE const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 b{1.5f, 1.5f, 2.5f}; CE const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f}; CE const Vector3 c{2.0f, 1.5f, 1.0f};
const Vector4 eq = Math::planeEquation(a, b, c); const Vector4 eq = Math::planeEquation(a, b, c);
CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f); CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f);
@ -296,12 +314,12 @@ void Vector4Test::planeEquationThreePoints() {
} }
void Vector4Test::planeEquationNormalPoint() { void Vector4Test::planeEquationNormalPoint() {
const Vector3 a{1.0f, 0.5f, 3.0f}; CE const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 normal{-0.9045340f, 0.3015113f, -0.3015113f}; CE const Vector3 normal{-0.9045340f, 0.3015113f, -0.3015113f};
const Vector4 eq = Math::planeEquation(normal, a); CE const Vector4 eq = Math::planeEquation(normal, a);
const Vector3 b{1.5f, 1.5f, 2.5f}; CE const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f}; 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(a, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(b, 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); CORRADE_COMPARE(Math::dot(c, eq.xyz()) + eq.w(), 0.0f);
@ -310,9 +328,9 @@ void Vector4Test::planeEquationNormalPoint() {
void Vector4Test::strictWeakOrdering() { void Vector4Test::strictWeakOrdering() {
StrictWeakOrdering o; StrictWeakOrdering o;
const Vector4 v4a{1.0f, 2.0f, 3.0f, 4.0f}; CE const Vector4 v4a{1.0f, 2.0f, 3.0f, 4.0f};
const Vector4 v4b{2.0f, 3.0f, 4.0f, 5.0f}; CE 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 v4c{1.0f, 2.0f, 3.0f, 5.0f};
CORRADE_VERIFY( o(v4a, v4b)); CORRADE_VERIFY( o(v4a, v4b));
CORRADE_VERIFY(!o(v4b, v4a)); CORRADE_VERIFY(!o(v4b, v4a));
@ -335,6 +353,11 @@ void Vector4Test::debug() {
Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f); Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n"); 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/Vector.h"
#include "Magnum/Math/StrictWeakOrdering.h" #include "Magnum/Math/StrictWeakOrdering.h"
#include "Cpp14VectorTest.h"
struct Vec3 { struct Vec3 {
float x, y, z; float x, y, z;
}; };
@ -58,6 +60,7 @@ namespace Test { namespace {
struct VectorTest: Corrade::TestSuite::Tester { struct VectorTest: Corrade::TestSuite::Tester {
explicit VectorTest(); explicit VectorTest();
#ifndef SKIP_TESTING
void construct(); void construct();
void constructFromData(); void constructFromData();
void constructPad(); void constructPad();
@ -119,6 +122,9 @@ struct VectorTest: Corrade::TestSuite::Tester {
void debug(); void debug();
void debugPacked(); void debugPacked();
#else
void skipTesting();
#endif
}; };
typedef Math::Constants<Float> Constants; typedef Math::Constants<Float> Constants;
@ -133,7 +139,14 @@ typedef Vector<4, Int> Vector4i;
using namespace Literals; using namespace Literals;
VectorTest::VectorTest() { VectorTest::VectorTest() {
addTests({&VectorTest::construct, #ifndef TESTING_CONSTEXPR
setTestName("MathVectorTest");
#else
setTestName("Cpp14MathVectorTest");
#endif
addTests({
#ifndef SKIP_TESTING
&VectorTest::construct,
&VectorTest::constructFromData, &VectorTest::constructFromData,
&VectorTest::constructPad, &VectorTest::constructPad,
&VectorTest::constructPadDefaultHalf, &VectorTest::constructPadDefaultHalf,
@ -193,9 +206,14 @@ VectorTest::VectorTest() {
&VectorTest::strictWeakOrdering, &VectorTest::strictWeakOrdering,
&VectorTest::debug, &VectorTest::debug,
&VectorTest::debugPacked}); &VectorTest::debugPacked
#else
&VectorTest::skipTesting
#endif
});
} }
#ifndef SKIP_TESTING
void VectorTest::construct() { void VectorTest::construct() {
constexpr Vector4 a = {1.0f, 2.0f, -3.0f, 4.5f}; constexpr Vector4 a = {1.0f, 2.0f, -3.0f, 4.5f};
CORRADE_COMPARE(a, Vector4(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<3> BitVector3;
typedef BitVector<4> BitVector4; typedef BitVector<4> BitVector4;
Vector4 a{1.0f, -3.5f, 5.0f, -10.0f}; CE 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}; CE 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 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, b), BitVector4{0xf});
CORRADE_COMPARE(equal(a, c), BitVector4{0xa}); CORRADE_COMPARE(equal(a, c), BitVector4{0xa});
CORRADE_COMPARE(notEqual(a, b), BitVector4{0x0}); CORRADE_COMPARE(notEqual(a, b), BitVector4{0x0});
@ -400,31 +418,31 @@ void VectorTest::promotedNegated() {
} }
void VectorTest::addSubtract() { void VectorTest::addSubtract() {
Vector4 a(1.0f, -3.0f, 5.0f, -10.0f); CE Vector4 a(1.0f, -3.0f, 5.0f, -10.0f);
Vector4 b(7.5f, 33.0f, -15.0f, 0.0f); CE Vector4 b(7.5f, 33.0f, -15.0f, 0.0f);
Vector4 c(8.5f, 30.0f, -10.0f, -10.0f); CE Vector4 c(8.5f, 30.0f, -10.0f, -10.0f);
CORRADE_COMPARE(a + b, c); CORRADE_COMPARE(a + b, c);
CORRADE_COMPARE(c - b, a); CORRADE_COMPARE(c - b, a);
} }
void VectorTest::multiplyDivide() { void VectorTest::multiplyDivide() {
Vector4 vector(1.0f, 2.0f, 3.0f, 4.0f); CE Vector4 vector(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); CE Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vector*-1.5f, multiplied); CORRADE_COMPARE(vector*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vector); CORRADE_COMPARE(multiplied/-1.5f, vector);
/* Divide vector with number and invert */ /* Divide vector with number and invert */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f); CE Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f); CE Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result); CORRADE_COMPARE(1.0f/divisor, result);
} }
void VectorTest::multiplyDivideIntegral() { void VectorTest::multiplyDivideIntegral() {
Vector4i vector(32, 10, -6, 2); CE Vector4i vector(32, 10, -6, 2);
Vector4i multiplied(-48, -15, 9, -3); CE Vector4i multiplied(-48, -15, 9, -3);
CORRADE_COMPARE(vector*-1.5f, multiplied); CORRADE_COMPARE(vector*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
@ -434,18 +452,18 @@ void VectorTest::multiplyDivideIntegral() {
} }
void VectorTest::multiplyDivideComponentWise() { void VectorTest::multiplyDivideComponentWise() {
Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f); CE Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f); CE Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f);
Vector4 multiplied(7.0f, -8.0f, -4.5f, 4.0f); CE Vector4 multiplied(7.0f, -8.0f, -4.5f, 4.0f);
CORRADE_COMPARE(vec*multiplier, multiplied); CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplied/multiplier, vec); CORRADE_COMPARE(multiplied/multiplier, vec);
} }
void VectorTest::multiplyDivideComponentWiseIntegral() { void VectorTest::multiplyDivideComponentWiseIntegral() {
Vector4i vec(7, 2, -16, -1); CE Vector4i vec(7, 2, -16, -1);
Vector4 multiplier(2.0f, -1.5f, 0.5f, 10.0f); CE Vector4 multiplier(2.0f, -1.5f, 0.5f, 10.0f);
Vector4i multiplied(14, -3, -8, -10); CE Vector4i multiplied(14, -3, -8, -10);
CORRADE_COMPARE(vec*multiplier, multiplied); CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplier*vec, multiplied); CORRADE_COMPARE(multiplier*vec, multiplied);
@ -457,8 +475,8 @@ void VectorTest::multiplyDivideComponentWiseIntegral() {
void VectorTest::modulo() { void VectorTest::modulo() {
typedef Math::Vector<2, Int> Vector2i; typedef Math::Vector<2, Int> Vector2i;
const Vector2i a(4, 13); CE const Vector2i a(4, 13);
const Vector2i b(2, 5); CE const Vector2i b(2, 5);
CORRADE_COMPARE(a % 2, Vector2i(0, 1)); CORRADE_COMPARE(a % 2, Vector2i(0, 1));
CORRADE_COMPARE(a % b, Vector2i(0, 3)); CORRADE_COMPARE(a % b, Vector2i(0, 3));
} }
@ -466,14 +484,14 @@ void VectorTest::modulo() {
void VectorTest::bitwise() { void VectorTest::bitwise() {
typedef Math::Vector<2, Int> Vector2i; typedef Math::Vector<2, Int> Vector2i;
const Vector2i a(85, 240); CE const Vector2i a(85, 240);
const Vector2i b(170, 85); CE const Vector2i b(170, 85);
CORRADE_COMPARE(~a, Vector2i(-86, -241)); CORRADE_COMPARE(~a, Vector2i(-86, -241));
CORRADE_COMPARE(a & b, Vector2i(0, 80)); CORRADE_COMPARE(a & b, Vector2i(0, 80));
CORRADE_COMPARE(a | b, Vector2i(255, 245)); CORRADE_COMPARE(a | b, Vector2i(255, 245));
CORRADE_COMPARE(a ^ b, Vector2i(255, 165)); 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(28, 128));
CORRADE_COMPARE(c >> 2, Vector2i(1, 8)); CORRADE_COMPARE(c >> 2, Vector2i(1, 8));
} }
@ -487,11 +505,13 @@ void VectorTest::dotSelf() {
} }
void VectorTest::length() { 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() { 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() { void VectorTest::normalized() {
@ -525,7 +545,7 @@ void VectorTest::max() {
} }
void VectorTest::minmax() { 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, 2.0f, -3.0f}.minmax()), expected);
CORRADE_COMPARE((Vector3{-1.0f, -3.0f, 2.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); CORRADE_COMPARE((Vector3{2.0f, -1.0f, -3.0f}.minmax()), expected);
@ -535,9 +555,9 @@ void VectorTest::minmax() {
} }
void VectorTest::nanIgnoring() { void VectorTest::nanIgnoring() {
Vector3 oneNan{1.0f, Constants::nan(), -3.0f}; CE Vector3 oneNan{1.0f, Constants::nan(), -3.0f};
Vector3 firstNan{Constants::nan(), 1.0f, -3.0f}; CE Vector3 firstNan{Constants::nan(), 1.0f, -3.0f};
Vector3 allNan{Constants::nan(), Constants::nan(), Constants::nan()}; CE Vector3 allNan{Constants::nan(), Constants::nan(), Constants::nan()};
CORRADE_COMPARE(oneNan.min(), -3.0f); CORRADE_COMPARE(oneNan.min(), -3.0f);
CORRADE_COMPARE(firstNan.min(), -3.0f); CORRADE_COMPARE(firstNan.min(), -3.0f);
@ -555,16 +575,16 @@ void VectorTest::nanIgnoring() {
} }
void VectorTest::projected() { void VectorTest::projected() {
Vector3 line(1.0f, -1.0f, 0.5f); CE Vector3 line(1.0f, -1.0f, 0.5f);
Vector3 projected = Vector3(1.0f, 2.0f, 3.0f).projected(line); 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, Vector3(0.222222f, -0.222222f, 0.111111f));
CORRADE_COMPARE(projected.normalized(), line.normalized()); CORRADE_COMPARE(projected.normalized(), line.normalized());
} }
void VectorTest::projectedOntoNormalized() { void VectorTest::projectedOntoNormalized() {
Vector3 vector(1.0f, 2.0f, 3.0f); CE Vector3 vector(1.0f, 2.0f, 3.0f);
Vector3 line(1.0f, -1.0f, 0.5f); CE Vector3 line(1.0f, -1.0f, 0.5f);
Vector3 projected = vector.projectedOntoNormalized(line.normalized()); Vector3 projected = vector.projectedOntoNormalized(line.normalized());
CORRADE_COMPARE(projected, Vector3(0.222222f, -0.222222f, 0.111111f)); 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 /* 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 would cause acos() to return a NaN. Ensure it's clamped to correct range
before passing it there. */ 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_VERIFY(a.isNormalized());
CORRADE_COMPARE(Math::angle(a, a), 0.0_radf); 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(data)), Vec2&>::value);
CORRADE_VERIFY(std::is_same<decltype(Vec2::from(cdata)), const 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); CORRADE_VERIFY(std::is_same<decltype(Vec2::pad(one)), Vec2>::value);
/* Const operators */ /* Const operators */
const Vec2 c; CE const Vec2 c;
const Vec2 c2; 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), Vec2>::value); CORRADE_VERIFY(std::is_same<decltype(-c), Vec2>::value);
CORRADE_VERIFY(std::is_same<decltype(c + 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(); 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"); 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 types and doing equality comparison on integral types. Scalar complement to
@ref equal(const Vector<size, T>& a, const Vector<size, T>&). @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); 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 types and doing equality comparison on integral types. Scalar complement to
@ref notEqual(const Vector<size, T>& a, const Vector<size, T>&). @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); return !TypeTraits<T>::equals(a, b);
} }
@ -467,17 +467,18 @@ namespace Implementation {
template<class T> struct TypeTraitsFloatingPoint: TypeTraitsName<T> { template<class T> struct TypeTraitsFloatingPoint: TypeTraitsName<T> {
TypeTraitsFloatingPoint() = delete; TypeTraitsFloatingPoint() = delete;
static bool equals(T a, T b); static constexpr inline T abs(T x) { return x < 0 ? -x : x; }
static bool equalsZero(T a, T epsilon); 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) */ /* Shortcut for binary equality (also infinites) */
if(a == b) return true; if(a == b) return true;
const T absA = std::abs(a); const T absA = abs(a);
const T absB = std::abs(b); const T absB = abs(b);
const T difference = std::abs(a - b); const T difference = abs(a - b);
/* One of the numbers is zero or both are extremely close to it, relative /* One of the numbers is zero or both are extremely close to it, relative
error is meaningless */ 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(); 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 */ /* Shortcut for binary equality */
if(a == T(0.0)) return true; 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 */ /* The value is extremely close to zero, relative error is meaningless */
if(absA < TypeTraits<T>::epsilon()) 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 - 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, 1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */ it's omitted. */
template<class T> inline bool isNormalizedSquared(T lengthSquared) { template<class T> constexpr inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon(); 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 { namespace Implementation {
template<std::size_t, class, class> struct VectorConverter; template<std::size_t, class, class> struct VectorConverter;
/* Needed by DualQuaternion and Functions.h (to avoid dependency between them) */ /* 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); return T((U(1) - t)*a + t*b);
} }
template<bool integral> struct IsZero; template<bool integral> struct IsZero;
template<> struct IsZero<false> { 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 /* Proper comparison should be with epsilon^2, but the value is not
representable in given precision. Comparing to epsilon instead. */ 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<> 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>{}; return vec == Vector<size, T>{};
} }
}; };
@ -101,7 +102,7 @@ the same general direction, `1` when two *normalized* vectors are parallel,
@f] @f]
@see @ref Vector::dot() const, @ref Vector::operator-(), @ref Vector2::perpendicular() @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{}; T out{};
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
out += a._data[i]*b._data[i]; out += a._data[i]*b._data[i];
@ -245,7 +246,7 @@ template<std::size_t size, class T> class Vector {
T* data(); T* data();
constexpr const T* data() const; /**< @overload */ constexpr const T* data() const; /**< @overload */
#else #else
auto data() -> T(&)[size] { return _data; } MAGNUM_CONSTEXPR14 auto data() -> T(&)[size] { return _data; }
constexpr auto data() const -> const T(&)[size] { return _data; } constexpr auto data() const -> const T(&)[size] { return _data; }
#endif #endif
@ -254,7 +255,7 @@ template<std::size_t size, class T> class Vector {
* *
* @see @ref data() * @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 */ 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() * @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) for(std::size_t i = 0; i != size; ++i)
if(!TypeTraits<T>::equals(_data[i], other._data[i])) return false; 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. * Returns the value as-is.
*/ */
Vector<size, T> operator+() const { return *this; } MAGNUM_CONSTEXPR14 Vector<size, T> operator+() const { return *this; }
/** /**
* @brief Negated vector * @brief Negated vector
@ -349,7 +350,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> Vector<size, T>
#else #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 #endif
operator-() const; operator-() const;
@ -360,7 +361,7 @@ template<std::size_t size, class T> class Vector {
* \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i * \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i
* @f] * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] += other._data[i]; _data[i] += other._data[i];
@ -372,7 +373,7 @@ template<std::size_t size, class T> class Vector {
* *
* @see @ref operator+=(), @ref sum() * @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; 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 * \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i
* @f] * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] -= other._data[i]; _data[i] -= other._data[i];
@ -395,7 +396,7 @@ template<std::size_t size, class T> class Vector {
* *
* @see @ref operator-=() * @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; 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>&), * @see @ref operator*=(const Vector<size, T>&),
* @ref operator*=(Vector<size, Integral>&, FloatingPoint) * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] *= scalar; _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*=(T), @ref operator*(T, const Vector<size, T>&),
* @ref operator*(const Vector<size, Integral>&, FloatingPoint) * @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; 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>&), * @see @ref operator/=(const Vector<size, T>&),
* @ref operator/=(Vector<size, Integral>&, FloatingPoint) * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] /= scalar; _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/=(T), @ref operator/(T, const Vector<size, T>&),
* @ref operator/(const Vector<size, Integral>&, FloatingPoint) * @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; return Vector<size, T>(*this) /= scalar;
} }
@ -462,7 +463,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator*=(T), * @see @ref operator*=(T),
* @ref operator*=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&) * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] *= other._data[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 operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&),
* @ref product() * @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; return Vector<size, T>(*this) *= other;
} }
@ -489,7 +490,7 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator/=(T), * @see @ref operator/=(T),
* @ref operator/=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&) * @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) for(std::size_t i = 0; i != size; ++i)
_data[i] /= other._data[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>&), * @see @ref operator/(T) const, @ref operator/=(const Vector<size, T>&),
* @ref operator/(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&) * @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; 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 isNormalized(), @ref Distance::pointPointSquared(),
* @ref Intersection::pointSphere() * @ref Intersection::pointSphere()
*/ */
T dot() const { return Math::dot(*this, *this); } MAGNUM_CONSTEXPR14 T dot() const { return Math::dot(*this, *this); }
/** /**
* @brief Vector length * @brief Vector length
@ -544,7 +545,7 @@ template<std::size_t size, class T> class Vector {
* @ref Intersection::pointSphere() * @ref Intersection::pointSphere()
* @todo something like std::hypot() for possibly better precision? * @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 * @brief Inverse vector length
@ -558,7 +559,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #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 #endif
lengthInverted() const { return T(1)/length(); } lengthInverted() const { return T(1)/length(); }
@ -572,7 +573,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> Vector<size, T>
#else #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 #endif
normalized() const { return *this*lengthInverted(); } normalized() const { return *this*lengthInverted(); }
@ -590,7 +591,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> Vector<size, T>
#else #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 #endif
resized(T length) const { resized(T length) const {
return *this*(lengthInverted()*length); return *this*(lengthInverted()*length);
@ -608,7 +609,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> Vector<size, T>
#else #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 #endif
projected(const Vector<size, T>& line) const { projected(const Vector<size, T>& line) const {
return line*Math::dot(*this, line)/line.dot(); 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> Vector<size, T>
#else #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 #endif
projectedOntoNormalized(const Vector<size, T>& line) const; 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() * @see @ref operator+(), @ref length()
*/ */
T sum() const; MAGNUM_CONSTEXPR14 T sum() const;
/** /**
* @brief Product of values in the vector * @brief Product of values in the vector
* *
* @see @ref operator*(const Vector<size, T>&) const * @see @ref operator*(const Vector<size, T>&) const
*/ */
T product() const; MAGNUM_CONSTEXPR14 T product() const;
/** /**
* @brief Minimal value in the vector * @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. * <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref Math::min(), @ref minmax(), @ref Math::isNan() * @see @ref Math::min(), @ref minmax(), @ref Math::isNan()
*/ */
T min() const; MAGNUM_CONSTEXPR14 T min() const;
/** /**
* @brief Maximal value in the vector * @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. * <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref Math::max(), @ref minmax(), @ref Math::isNan() * @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 * @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. * <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() * @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 #ifndef DOXYGEN_GENERATING_OUTPUT
protected: 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_> 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 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>&) */ /* 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])...} {} 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. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #else
@ -783,7 +784,7 @@ template<std::size_t size, class T> inline Vector<size, T> operator*(
@f] @f]
@see @ref Vector::operator/(T) const @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 #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #else
@ -804,7 +805,7 @@ template<std::size_t size, class T> inline Vector<size, T> operator/(
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -820,7 +821,7 @@ operator%=(Vector<size, Integral>& a, Integral b) {
/** @relates Vector /** @relates Vector
@brief Modulo of an integral 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -836,7 +837,7 @@ operator%(const Vector<size, Integral>& a, Integral b) {
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -852,7 +853,7 @@ operator%=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector /** @relates Vector
@brief Modulo of two integral vectors @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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -866,7 +867,7 @@ operator%(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector /** @relates Vector
@brief Bitwise NOT of an integral 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -886,7 +887,7 @@ operator~(const Vector<size, Integral>& vector) {
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -902,7 +903,7 @@ operator&=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector /** @relates Vector
@brief Bitwise AND of two integral vectors @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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -918,7 +919,7 @@ operator&(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -934,7 +935,7 @@ operator|=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector /** @relates Vector
@brief Bitwise OR of two integral vectors @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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -950,7 +951,7 @@ operator|(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -966,7 +967,7 @@ operator^=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
/** @relates Vector /** @relates Vector
@brief Bitwise XOR of two integral vectors @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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -982,7 +983,7 @@ operator^(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -1005,7 +1006,7 @@ operator<<=(Vector<size, Integral>& vector,
/** @relates Vector /** @relates Vector
@brief Bitwise left shift of an integral 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -1028,7 +1029,7 @@ operator<<(const Vector<size, Integral>& vector,
The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -1050,7 +1051,7 @@ operator>>=(Vector<size, Integral>& vector,
/** @relates Vector /** @relates Vector
@brief Bitwise left shift of an integral 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -1073,7 +1074,7 @@ operator>>(const Vector<size, Integral>& vector,
Similar to @ref Vector::operator*=(T), except that the multiplication is done Similar to @ref Vector::operator*=(T), except that the multiplication is done
in floating-point. The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #else
@ -1092,7 +1093,7 @@ operator*=(Vector<size, Integral>& vector, FloatingPoint scalar) {
Similar to @ref Vector::operator*(T) const, except that the multiplication is Similar to @ref Vector::operator*(T) const, except that the multiplication is
done in floating-point. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -1108,7 +1109,7 @@ operator*(const Vector<size, Integral>& vector, FloatingPoint scalar) {
Same as @ref operator*(const Vector<size, Integral>&, FloatingPoint). 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #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 Similar to @ref Vector::operator/=(T), except that the division is done in
floating-point. The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #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 Similar to @ref Vector::operator/(T) const, except that the division is done in
floating-point. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #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 Similar to @ref Vector::operator*=(const Vector<size, T>&), except that the
multiplication is done in floating-point. The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #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 vector, convert both arguments to the same floating-point type to have
floating-point result. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #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>&). 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #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 Similar to @ref Vector::operator/=(const Vector<size, T>&), except that the
division is done in floating-point. The computation is done in-place. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>& Vector<size, Integral>&
#else #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 convert both arguments to the same floating-point type to have floating-point
result. 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral> Vector<size, Integral>
#else #else
@ -1288,66 +1289,66 @@ extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utili
return Math::Vector<size, T>::pad(a, value); \ return Math::Vector<size, T>::pad(a, value); \
} \ } \
\ \
Type<T> operator+() const { \ constexpr Type<T> operator+() const { \
return Math::Vector<size, T>::operator+(); \ return Math::Vector<size, T>::operator+(); \
} \ } \
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Type<T>>::type \ template<class U = T> typename std::enable_if<std::is_signed<U>::value, Type<T>>::type \
operator-() const { \ constexpr operator-() const { \
return Math::Vector<size, T>::operator-(); \ 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); \ Math::Vector<size, T>::operator+=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator-=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator*=(number); \
return *this; \ return *this; \
} \ } \
Type<T> operator*(T number) const { \ constexpr Type<T> operator*(T number) const { \
return Math::Vector<size, T>::operator*(number); \ 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); \ Math::Vector<size, T>::operator/=(number); \
return *this; \ return *this; \
} \ } \
Type<T> operator/(T number) const { \ constexpr Type<T> operator/(T number) const { \
return Math::Vector<size, T>::operator/(number); \ 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); \ Math::Vector<size, T>::operator*=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator/=(other); \
return *this; \ 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); \ 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(); \ 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); \ 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); \ 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); \ return Math::Vector<size, T>::projectedOntoNormalized(other); \
} \ } \
constexpr Type<T> flipped() const { \ 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) \ #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); \ 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); \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \ 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; \ 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); \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) &= b; \
return a; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) |= b; \
return a; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) ^= b; \
return a; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(vector) <<= shift; \
return vector; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(vector) >>= shift; \
return vector; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(vector) *= number; \
return vector; \ 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; \ 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); \ 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; \ static_cast<Math::Vector<size, Integral>&>(vector) /= number; \
return vector; \ 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; \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) *= b; \
return a; \ 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; \ 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); \ 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; \ static_cast<Math::Vector<size, Integral>&>(a) /= b; \
return a; \ 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; \ return static_cast<const Math::Vector<size, Integral>&>(a)/b; \
} }
#endif #endif
@ -1494,7 +1495,7 @@ inline Vector<size, T>
#else #else
template<class U> inline typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type template<class U> inline typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif #endif
Vector<size, T>::operator-() const { MAGNUM_CONSTEXPR14 Vector<size, T>::operator-() const {
Vector<size, T> out; Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
@ -1507,7 +1508,7 @@ template<std::size_t size, class T>
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T> inline Vector<size, T>
#else #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 #endif
Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const { Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(), CORRADE_ASSERT(line.isNormalized(),
@ -1515,7 +1516,7 @@ Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
return line*Math::dot(*this, line); 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]); T out(_data[0]);
for(std::size_t i = 1; i != size; ++i) 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; 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]); T out(_data[0]);
for(std::size_t i = 1; i != size; ++i) 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>{}); std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T out(_data[i]); T out(_data[i]);
@ -1559,7 +1560,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::min() const {
return out; 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>{}); std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T out(_data[i]); T out(_data[i]);
@ -1569,7 +1570,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::max() const {
return out; 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>{}); std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T min{_data[i]}, max{_data[i]}; T min{_data[i]}, max{_data[i]};

12
src/Magnum/Math/Vector2.h

@ -51,7 +51,7 @@ for more information.
@see @ref Vector2::perpendicular(), @see @ref Vector2::perpendicular(),
@ref dot(const Vector<size, T>&, const Vector<size, T>&) @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]; 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 */ /** @brief Copy constructor */
constexpr /*implicit*/ Vector2(const Vector<2, T>& other) noexcept: Vector<2, T>(other) {} 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 */ 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 */ 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 #ifdef DOXYGEN_GENERATING_OUTPUT
Vector2<T> Vector2<T>
#else #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 #endif
perpendicular() const { return {-y(), x()}; } perpendicular() const { return {-y(), x()}; }
@ -181,14 +181,14 @@ template<class T> class Vector2: public Vector<2, T> {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #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 #endif
aspectRatio() const { return x()/y(); } aspectRatio() const { return x()/y(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2)
private: 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 #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. for more information.
@see @ref cross(const Vector2<T>&, const Vector2<T>&), @ref planeEquation() @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 { return {
a._data[1]*b._data[2] - b._data[1]*a._data[2], a._data[1]*b._data[2] - b._data[1]*a._data[2],
a._data[2]*b._data[0] - b._data[2]*a._data[0], 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() * @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 */ 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() * @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 */ 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() * @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 */ 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(). * 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 */ 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(). * 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 */ 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(). * 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 */ 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() * @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 { constexpr const Vector2<T> xy() const {
return {Vector<3, T>::_data[0], Vector<3, T>::_data[1]}; return {Vector<3, T>::_data[0], Vector<3, T>::_data[1]};
} /**< @overload */ } /**< @overload */
@ -237,7 +237,7 @@ template<class T> class Vector3: public Vector<3, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Vector3) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Vector3)
private: 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 #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() * @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 */ 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() * @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 */ 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() * @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 */ 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() * @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 */ 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(). * 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 */ 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(). * 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 */ 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(). * 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 */ 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(). * 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 */ 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() * @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 { constexpr const Vector3<T> xyz() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]}; return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
} /**< @overload */ } /**< @overload */
@ -197,7 +197,7 @@ template<class T> class Vector4: public Vector<4, T> {
* Equivalent to @ref xyz(). * Equivalent to @ref xyz().
* @see @ref gather(), @ref scatter() * @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 { constexpr const Vector3<T> rgb() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]}; return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
} /**< @overload */ } /**< @overload */
@ -208,7 +208,7 @@ template<class T> class Vector4: public Vector<4, T> {
* *
* @see @ref gather(), @ref scatter() * @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 { constexpr const Vector2<T> xy() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1]}; return {Vector<4, T>::_data[0], Vector<4, T>::_data[1]};
} /**< @overload */ } /**< @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(), @see @ref planeEquation(const Vector3<T>&, const Vector3<T>&), @ref cross(),
@ref dot() @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(); const Vector3<T> normal = Math::cross(p1 - p0, p2 - p0).normalized();
return {normal, -Math::dot(normal, p0)}; 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>&), @see @ref planeEquation(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&),
@ref dot(), @ref Frustum @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)}; return {normal, -Math::dot(normal, point)};
} }

Loading…
Cancel
Save