Browse Source

Math: make const Vector operators constexpr.

Need to make a constexpr style data for the UI library and it involves
various multiplications and such, so took that as an opportunity to
enable constexpr on all operators. No other functions such as max() so
far, as I don't really need those yet.

After a few abandoned iterations that involved adding constexpr
overloads only to the Vector2, Vector3 and Vector4 subclasses I ended up
with a rather minimal solution that makes the base Vector constexpr
already, and just about 50 extra lines in total.

In the original code from 2010, to avoid redundant code, the const
operations were delegating to compound assignment operations, i.e.
operator*() being implemented by making a copy of itself and then
delegating to operator*=(). Thus, as far as a Debug build is concerned,
one extra indirection for each. The new solution is *also* one
indirection (which is needed in order to expand the variadic sequence)
so it's not worse in Debug in any way, however it's one indirection less
in the Vector2, Vector3 and Vector4 subclasses as there it delegates
directly to the internal implementation instead of the base class
operator. On GCC at least, there's no measurable impact on build times
either -- the whole project builds in ~2:22 both before and after this
change.

The way the change is done also allows the new code to be compiled out
if C++14 constexpr is enabled, where the functions would simply delegate
to the compound assignments. I'm not planning to touch that any time
soon either.
pull/168/head
Vladimír Vondruš 2 years ago
parent
commit
6f69ab8e29
  1. 13
      src/Magnum/Math/Test/ColorTest.cpp
  2. 8
      src/Magnum/Math/Test/Vector2Test.cpp
  3. 8
      src/Magnum/Math/Test/Vector3Test.cpp
  4. 8
      src/Magnum/Math/Test/Vector4Test.cpp
  5. 174
      src/Magnum/Math/Test/VectorTest.cpp
  6. 384
      src/Magnum/Math/Vector.h

13
src/Magnum/Math/Test/ColorTest.cpp

@ -1088,6 +1088,19 @@ void ColorTest::multiplyDivideIntegral() {
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector3, multiplied3); CORRADE_COMPARE(-1.5f*vector3, multiplied3);
CORRADE_COMPARE(-1.5f*vector4, multiplied4); CORRADE_COMPARE(-1.5f*vector4, multiplied4);
constexpr Color3i cvector3{32, 10, -6};
constexpr Color4i cvector4{32, 10, -6, 2};
constexpr Color3i ca31 = cvector3*-1.5f;
constexpr Color4i ca41 = cvector4*-1.5f;
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
constexpr Color3i ca32 = -1.5f*cvector3;
constexpr Color4i ca42 = -1.5f*cvector4;
CORRADE_COMPARE(ca31, multiplied3);
CORRADE_COMPARE(ca41, multiplied4);
CORRADE_COMPARE(ca32, multiplied3);
CORRADE_COMPARE(ca42, multiplied4);
} }
void ColorTest::strictWeakOrdering() { void ColorTest::strictWeakOrdering() {

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

@ -261,6 +261,14 @@ void Vector2Test::multiplyDivideIntegral() {
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
constexpr Vector2i cvector{32, -6};
constexpr Vector2i ca1 = cvector*-1.5f;
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
constexpr Vector2i ca2 = -1.5f*cvector;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
} }
void Vector2Test::strictWeakOrdering() { void Vector2Test::strictWeakOrdering() {

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

@ -285,6 +285,14 @@ void Vector3Test::multiplyDivideIntegral() {
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
constexpr Vector3i cvector{32, 10, -6};
constexpr Vector3i ca1 = cvector*-1.5f;
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
constexpr Vector3i ca2 = -1.5f*cvector;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
} }
void Vector3Test::strictWeakOrdering() { void Vector3Test::strictWeakOrdering() {

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

@ -299,6 +299,14 @@ void Vector4Test::multiplyDivideIntegral() {
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
constexpr Vector4i cvector{32, 10, -6, 2};
constexpr Vector4i ca1 = cvector*-1.5f;
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
constexpr Vector4i ca2 = -1.5f*cvector;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
} }
void Vector4Test::planeEquationThreePoints() { void Vector4Test::planeEquationThreePoints() {

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

@ -407,7 +407,9 @@ void VectorTest::promotedNegated() {
constexpr Vector4 a{1.0f, -3.0f, 5.0f, -10.0f}; constexpr Vector4 a{1.0f, -3.0f, 5.0f, -10.0f};
constexpr Vector4 promotedA = +a; constexpr Vector4 promotedA = +a;
constexpr Vector4 negatedA = -a;
CORRADE_COMPARE(promotedA, a); CORRADE_COMPARE(promotedA, a);
CORRADE_COMPARE(negatedA, (Vector4{-1.0f, 3.0f, -5.0f, 10.0f}));
} }
void VectorTest::addSubtract() { void VectorTest::addSubtract() {
@ -426,6 +428,15 @@ void VectorTest::addSubtract() {
CORRADE_COMPARE(&(v -= b), &v); CORRADE_COMPARE(&(v -= b), &v);
CORRADE_COMPARE(v, a); CORRADE_COMPARE(v, a);
} }
constexpr Vector4 ca{1.0f, -3.0f, 5.0f, -10.0f};
constexpr Vector4 cb{7.5f, 33.0f, -15.0f, 0.0f};
constexpr Vector4 cd = ca + cb;
CORRADE_COMPARE(cd, c);
constexpr Vector4 cc{8.5f, 30.0f, -10.0f, -10.0f};
constexpr Vector4 ce = cc - cb;
CORRADE_COMPARE(ce, a);
} }
void VectorTest::multiplyDivide() { void VectorTest::multiplyDivide() {
@ -447,10 +458,24 @@ void VectorTest::multiplyDivide() {
CORRADE_COMPARE(v, vector); CORRADE_COMPARE(v, vector);
} }
constexpr Vector4 cvector{1.0f, 2.0f, 3.0f, 4.0f};
constexpr Vector4 ca1 = cvector*-1.5f;
constexpr Vector4 ca2 = -1.5f*cvector;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
constexpr Vector4 cmultiplied{-1.5f, -3.0f, -4.5f, -6.0f};
constexpr Vector4 cb = cmultiplied/-1.5f;
CORRADE_COMPARE(cb, vector);
/* Divide a vector with a scalar and invert */ /* Divide a vector with a scalar and invert */
const Vector4 divisor{1.0f, 2.0f, -4.0f, 8.0f}; const Vector4 divisor{1.0f, 2.0f, -4.0f, 8.0f};
const Vector4 result{1.0f, 0.5f, -0.25f, 0.125f}; const Vector4 result{1.0f, 0.5f, -0.25f, 0.125f};
CORRADE_COMPARE(1.0f/divisor, result); CORRADE_COMPARE(1.0f/divisor, result);
constexpr Vector4 cdivisor(1.0f, 2.0f, -4.0f, 8.0f);
constexpr Vector4 ce = 1.0f/cdivisor;
CORRADE_COMPARE(ce, result);
} }
void VectorTest::multiplyDivideIntegral() { void VectorTest::multiplyDivideIntegral() {
@ -472,6 +497,16 @@ void VectorTest::multiplyDivideIntegral() {
CORRADE_COMPARE(v, vector); CORRADE_COMPARE(v, vector);
} }
constexpr Vector4i cvector{32, 10, -6, 2};
constexpr Vector4i ca1 = cvector*-1.5f;
constexpr Vector4i ca2 = -1.5f*cvector;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
constexpr Vector4i cmultiplied{-48, -15, 9, -3};
constexpr Vector4i cb = cmultiplied/-1.5f;
CORRADE_COMPARE(cb, cvector);
/* Using integer vector as divisor is not supported */ /* Using integer vector as divisor is not supported */
} }
@ -493,6 +528,14 @@ void VectorTest::multiplyDivideComponentWise() {
CORRADE_COMPARE(&(v /= multiplier), &v); CORRADE_COMPARE(&(v /= multiplier), &v);
CORRADE_COMPARE(v, vec); CORRADE_COMPARE(v, vec);
} }
constexpr Vector4 cvec{1.0f, 2.0f, 3.0f, 4.0f};
constexpr Vector4 cmultiplier{7.0f, -4.0f, -1.5f, 1.0f};
constexpr Vector4 cmultiplied{7.0f, -8.0f, -4.5f, 4.0f};
constexpr Vector4 ca = cvec*cmultiplier;
constexpr Vector4 cb = cmultiplied/cmultiplier;
CORRADE_COMPARE(ca, multiplied);
CORRADE_COMPARE(cb, vec);
} }
void VectorTest::multiplyDivideComponentWiseIntegral() { void VectorTest::multiplyDivideComponentWiseIntegral() {
@ -515,6 +558,17 @@ void VectorTest::multiplyDivideComponentWiseIntegral() {
CORRADE_COMPARE(v, vec); CORRADE_COMPARE(v, vec);
} }
constexpr Vector4i cvec{7, 2, -16, -1};
constexpr Vector4 cmultiplier{2.0f, -1.5f, 0.5f, 10.0f};
constexpr Vector4i ca1 = cvec*cmultiplier;
constexpr Vector4i ca2 = cmultiplier*cvec;
CORRADE_COMPARE(ca1, multiplied);
CORRADE_COMPARE(ca2, multiplied);
constexpr Vector4i cmultiplied{14, -3, -8, -10};
constexpr Vector4i cb = cmultiplied/cmultiplier;
CORRADE_COMPARE(cb, cvec);
/* Using integer vector as divisor is not supported */ /* Using integer vector as divisor is not supported */
} }
@ -535,6 +589,13 @@ void VectorTest::modulo() {
CORRADE_COMPARE(&(v %= b), &v); CORRADE_COMPARE(&(v %= b), &v);
CORRADE_COMPARE(v, (Vector4i{0, 3, 63, -2})); CORRADE_COMPARE(v, (Vector4i{0, 3, 63, -2}));
} }
constexpr Vector4i ca{4, 13, 255, -6};
constexpr Vector4i cb{2, 5, 64, -4};
constexpr Vector4i cc = ca % 2;
constexpr Vector4i cd = ca % cb;
CORRADE_COMPARE(cc, (Vector4i{0, 1, 1, 0}));
CORRADE_COMPARE(cd, (Vector4i{0, 3, 63, -2}));
} }
void VectorTest::bitwise() { void VectorTest::bitwise() {
@ -563,6 +624,17 @@ void VectorTest::bitwise() {
CORRADE_COMPARE(v, (Vector4i{255, 165, -254, -44})); CORRADE_COMPARE(v, (Vector4i{255, 165, -254, -44}));
} }
constexpr Vector4i ca{85, 240, -241, 33};
constexpr Vector4i cb{170, 85, 13, -11};
constexpr Vector4i cd = ~ca;
constexpr Vector4i ce = ca & cb;
constexpr Vector4i cf = ca | cb;
constexpr Vector4i cg = ca ^ cb;
CORRADE_COMPARE(cd, (Vector4i{-86, -241, 240, -34}));
CORRADE_COMPARE(ce, (Vector4i{0, 80, 13, 33}));
CORRADE_COMPARE(cf, (Vector4i{255, 245, -241, -11}));
CORRADE_COMPARE(cg, (Vector4i{255, 165, -254, -44}));
const Vector4i c{7, 32, 1, 15}; const Vector4i c{7, 32, 1, 15};
CORRADE_COMPARE(c << 2, (Vector4i{28, 128, 4, 60})); CORRADE_COMPARE(c << 2, (Vector4i{28, 128, 4, 60}));
{ {
@ -577,6 +649,12 @@ void VectorTest::bitwise() {
CORRADE_COMPARE(&(v >>= 2), &v); CORRADE_COMPARE(&(v >>= 2), &v);
CORRADE_COMPARE(v, (Vector4i{1, 8, 0, 3})); CORRADE_COMPARE(v, (Vector4i{1, 8, 0, 3}));
} }
constexpr Vector4i cc{7, 32, 1, 15};
constexpr Vector4i ch = cc << 2;
constexpr Vector4i ci = cc >> 2;
CORRADE_COMPARE(ch, (Vector4i{28, 128, 4, 60}));
CORRADE_COMPARE(ci, (Vector4i{1, 8, 0, 3}));
} }
void VectorTest::dot() { void VectorTest::dot() {
@ -855,6 +933,11 @@ void VectorTest::subclass() {
} }
CORRADE_COMPARE(-Vec2(-2.0f, 5.0f), Vec2(2.0f, -5.0f)); CORRADE_COMPARE(-Vec2(-2.0f, 5.0f), Vec2(2.0f, -5.0f));
{
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb = -ca;
CORRADE_COMPARE(cb, (Vec2{2.0f, -5.0f}));
}
/* Addition / subtraction */ /* Addition / subtraction */
CORRADE_COMPARE(Vec2(-2.0f, 5.0f) + Vec2(1.0f, -3.0f), Vec2(-1.0f, 2.0f)); CORRADE_COMPARE(Vec2(-2.0f, 5.0f) + Vec2(1.0f, -3.0f), Vec2(-1.0f, 2.0f));
@ -862,6 +945,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a += Vec2{1.0f, -3.0f}), &a); CORRADE_COMPARE(&(a += Vec2{1.0f, -3.0f}), &a);
CORRADE_COMPARE(a, (Vec2{-1.0f, 2.0f})); CORRADE_COMPARE(a, (Vec2{-1.0f, 2.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb{1.0f, -3.0f};
constexpr Vec2 cc = ca + cb;
CORRADE_COMPARE(cc, (Vec2{-1.0f, 2.0f}));
} }
CORRADE_COMPARE(Vec2(-2.0f, 5.0f) - Vec2(1.0f, -3.0f), Vec2(-3.0f, 8.0f)); CORRADE_COMPARE(Vec2(-2.0f, 5.0f) - Vec2(1.0f, -3.0f), Vec2(-3.0f, 8.0f));
@ -869,6 +957,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a -= Vec2{1.0f, -3.0f}), &a); CORRADE_COMPARE(&(a -= Vec2{1.0f, -3.0f}), &a);
CORRADE_COMPARE(a, (Vec2{-3.0f, 8.0f})); CORRADE_COMPARE(a, (Vec2{-3.0f, 8.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb{1.0f, -3.0f};
constexpr Vec2 cc = ca - cb;
CORRADE_COMPARE(cc, (Vec2{-3.0f, 8.0f}));
} }
/* Multiplication and division with a scalar */ /* Multiplication and division with a scalar */
@ -878,6 +971,12 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a *= 2.0f), &a); CORRADE_COMPARE(&(a *= 2.0f), &a);
CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f})); CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb1 = ca*2.0f;
constexpr Vec2 cb2 = 2.0f*ca;
CORRADE_COMPARE(cb1, (Vec2{-4.0f, 10.0f}));
CORRADE_COMPARE(cb2, (Vec2{-4.0f, 10.0f}));
} }
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/0.5f, Vec2(-4.0f, 10.0f)); CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/0.5f, Vec2(-4.0f, 10.0f));
@ -886,6 +985,12 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a /= 0.5f), &a); CORRADE_COMPARE(&(a /= 0.5f), &a);
CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f})); CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb1 = ca/0.5f;
constexpr Vec2 cb2 = 2.0f/ca;
CORRADE_COMPARE(cb1, (Vec2{-4.0f, 10.0f}));
CORRADE_COMPARE(cb2, (Vec2{-1.0f, 0.4f}));
} }
/* Multiplication/division with an integer scalar */ /* Multiplication/division with an integer scalar */
@ -895,6 +1000,12 @@ void VectorTest::subclass() {
Vec2i a{2, 4}; Vec2i a{2, 4};
CORRADE_COMPARE(&(a *= 1.5f), &a); CORRADE_COMPARE(&(a *= 1.5f), &a);
CORRADE_COMPARE(a, (Vec2i{3, 6})); CORRADE_COMPARE(a, (Vec2i{3, 6}));
constexpr Vec2i ca{2, 4};
constexpr Vec2i cb1 = ca*1.5f;
constexpr Vec2i cb2 = 1.5f*ca;
CORRADE_COMPARE(cb1, (Vec2i{3, 6}));
CORRADE_COMPARE(cb2, (Vec2i{3, 6}));
} }
{ {
@ -907,6 +1018,10 @@ void VectorTest::subclass() {
Vec2i a{2, 4}; Vec2i a{2, 4};
CORRADE_COMPARE(&(a /= (2.0f/3.0f)), &a); CORRADE_COMPARE(&(a /= (2.0f/3.0f)), &a);
CORRADE_COMPARE(a, (Vec2i{3, 6})); CORRADE_COMPARE(a, (Vec2i{3, 6}));
constexpr Vec2i ca{2, 4};
constexpr Vec2i cb = ca/(2.0f/3.0f);
CORRADE_COMPARE(cb, (Vec2i{3, 6}));
} }
/* Multiplication and division with a vector */ /* Multiplication and division with a vector */
@ -915,6 +1030,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a *= Vec2{1.5f, -2.0f}), &a); CORRADE_COMPARE(&(a *= Vec2{1.5f, -2.0f}), &a);
CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f})); CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb{1.5f, -2.0f};
constexpr Vec2 cc = ca*cb;
CORRADE_COMPARE(cc, (Vec2{-3.0f, -10.0f}));
} }
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/Vec2(2.0f/3.0f, -0.5f), Vec2(-3.0f, -10.0f)); CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/Vec2(2.0f/3.0f, -0.5f), Vec2(-3.0f, -10.0f));
@ -922,6 +1042,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f}; Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a /= Vec2{2.0f/3.0f, -0.5f}), &a); CORRADE_COMPARE(&(a /= Vec2{2.0f/3.0f, -0.5f}), &a);
CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f})); CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f}));
constexpr Vec2 ca{-2.0f, 5.0f};
constexpr Vec2 cb{2.0f/3.0f, -0.5f};
constexpr Vec2 cc = ca/cb;
CORRADE_COMPARE(cc, (Vec2{-3.0f, -10.0f}));
} }
/* Multiplication/division with an integer vector */ /* Multiplication/division with an integer vector */
@ -931,6 +1056,13 @@ void VectorTest::subclass() {
Vec2i a{2, 4}; Vec2i a{2, 4};
CORRADE_COMPARE(&(a *= Vec2{-1.5f, 0.5f}), &a); CORRADE_COMPARE(&(a *= Vec2{-1.5f, 0.5f}), &a);
CORRADE_COMPARE(a, (Vec2i{-3, 2})); CORRADE_COMPARE(a, (Vec2i{-3, 2}));
constexpr Vec2i ca{2, 4};
constexpr Vec2 cb{-1.5f, 0.5f};
constexpr Vec2i cc1 = ca*cb;
constexpr Vec2i cc2 = cb*ca;
CORRADE_COMPARE(cc1, (Vec2i{-3, 2}));
CORRADE_COMPARE(cc2, (Vec2i{-3, 2}));
} }
{ {
@ -943,6 +1075,11 @@ void VectorTest::subclass() {
Vec2i a{2, 4}; Vec2i a{2, 4};
CORRADE_COMPARE(&(a /= Vec2{-2.0f/3.0f, 2.0f}), &a); CORRADE_COMPARE(&(a /= Vec2{-2.0f/3.0f, 2.0f}), &a);
CORRADE_COMPARE(a, (Vec2i{-3, 2})); CORRADE_COMPARE(a, (Vec2i{-3, 2}));
constexpr Vec2i ca{2, 4};
constexpr Vec2 cb{-2.0f/3.0f, 2.0f};
constexpr Vec2i cc = ca/cb;
CORRADE_COMPARE(cc, (Vec2i{-3, 2}));
} }
/* Modulo operations */ /* Modulo operations */
@ -951,6 +1088,10 @@ void VectorTest::subclass() {
Vec2i a{4, 13}; Vec2i a{4, 13};
CORRADE_COMPARE(&(a %= 2), &a); CORRADE_COMPARE(&(a %= 2), &a);
CORRADE_COMPARE(a, (Vec2i{0, 1})); CORRADE_COMPARE(a, (Vec2i{0, 1}));
constexpr Vec2i ca{4, 13};
constexpr Vec2i cb = ca % 2;
CORRADE_COMPARE(cb, (Vec2i{0, 1}));
} }
CORRADE_COMPARE(Vec2i(4, 13) % Vec2i(2, 5), Vec2i(0, 3)); CORRADE_COMPARE(Vec2i(4, 13) % Vec2i(2, 5), Vec2i(0, 3));
@ -958,10 +1099,20 @@ void VectorTest::subclass() {
Vec2i a{4, 13}; Vec2i a{4, 13};
CORRADE_COMPARE(&(a %= Vec2i{2, 5}), &a); CORRADE_COMPARE(&(a %= Vec2i{2, 5}), &a);
CORRADE_COMPARE(a, (Vec2i{0, 3})); CORRADE_COMPARE(a, (Vec2i{0, 3}));
constexpr Vec2i ca{4, 13};
constexpr Vec2i cb{2, 5};
constexpr Vec2i cc = ca % cb;
CORRADE_COMPARE(cc, (Vec2i{0, 3}));
} }
/* Unary bitwise operations */ /* Unary bitwise operations */
CORRADE_COMPARE(~Vec2i(85, 240), Vec2i(-86, -241)); CORRADE_COMPARE(~Vec2i(85, 240), Vec2i(-86, -241));
{
constexpr Vec2i ca{85, 240};
constexpr Vec2i cb = ~ca;
CORRADE_COMPARE(cb, (Vec2i{-86, -241}));
}
/* Bitwise AND, OR and XOR */ /* Bitwise AND, OR and XOR */
CORRADE_COMPARE(Vec2i(85, 240) & Vec2i(170, 85), Vec2i(0, 80)); CORRADE_COMPARE(Vec2i(85, 240) & Vec2i(170, 85), Vec2i(0, 80));
@ -969,6 +1120,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240}; Vec2i a{85, 240};
CORRADE_COMPARE(&(a &= Vec2i{170, 85}), &a); CORRADE_COMPARE(&(a &= Vec2i{170, 85}), &a);
CORRADE_COMPARE(a, (Vec2i{0, 80})); CORRADE_COMPARE(a, (Vec2i{0, 80}));
constexpr Vec2i ca{85, 240};
constexpr Vec2i cb{170, 85};
constexpr Vec2i cc = ca & cb;
CORRADE_COMPARE(cc, (Vec2i{0, 80}));
} }
CORRADE_COMPARE(Vec2i(85, 240) | Vec2i(170, 85), Vec2i(255, 245)); CORRADE_COMPARE(Vec2i(85, 240) | Vec2i(170, 85), Vec2i(255, 245));
@ -976,6 +1132,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240}; Vec2i a{85, 240};
CORRADE_COMPARE(&(a |= Vec2i{170, 85}), &a); CORRADE_COMPARE(&(a |= Vec2i{170, 85}), &a);
CORRADE_COMPARE(a, (Vec2i{255, 245})); CORRADE_COMPARE(a, (Vec2i{255, 245}));
constexpr Vec2i ca{85, 240};
constexpr Vec2i cb{170, 85};
constexpr Vec2i cc = ca | cb;
CORRADE_COMPARE(cc, (Vec2i{255, 245}));
} }
CORRADE_COMPARE(Vec2i(85, 240) ^ Vec2i(170, 85), Vec2i(255, 165)); CORRADE_COMPARE(Vec2i(85, 240) ^ Vec2i(170, 85), Vec2i(255, 165));
@ -983,6 +1144,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240}; Vec2i a{85, 240};
CORRADE_COMPARE(&(a ^= Vec2i{170, 85}), &a); CORRADE_COMPARE(&(a ^= Vec2i{170, 85}), &a);
CORRADE_COMPARE(a, (Vec2i{255, 165})); CORRADE_COMPARE(a, (Vec2i{255, 165}));
constexpr Vec2i ca{85, 240};
constexpr Vec2i cb{170, 85};
constexpr Vec2i cc = ca ^ cb;
CORRADE_COMPARE(cc, (Vec2i{255, 165}));
} }
/* Bit shift */ /* Bit shift */
@ -991,6 +1157,10 @@ void VectorTest::subclass() {
Vec2i a{7, 32}; Vec2i a{7, 32};
CORRADE_COMPARE(&(a <<= 2), &a); CORRADE_COMPARE(&(a <<= 2), &a);
CORRADE_COMPARE(a, (Vec2i{28, 128})); CORRADE_COMPARE(a, (Vec2i{28, 128}));
constexpr Vec2i ca{7, 32};
constexpr Vec2i cb = ca << 2;
CORRADE_COMPARE(cb, (Vec2i{28, 128}));
} }
CORRADE_COMPARE(Vec2i(7, 32) >> 2, Vec2i(1, 8)); CORRADE_COMPARE(Vec2i(7, 32) >> 2, Vec2i(1, 8));
@ -998,6 +1168,10 @@ void VectorTest::subclass() {
Vec2i a{7, 32}; Vec2i a{7, 32};
CORRADE_COMPARE(&(a >>= 2), &a); CORRADE_COMPARE(&(a >>= 2), &a);
CORRADE_COMPARE(a, (Vec2i{1, 8})); CORRADE_COMPARE(a, (Vec2i{1, 8}));
constexpr Vec2i ca{7, 32};
constexpr Vec2i cb = ca >> 2;
CORRADE_COMPARE(cb, (Vec2i{1, 8}));
} }
/* Functions */ /* Functions */

384
src/Magnum/Math/Vector.h

@ -356,11 +356,13 @@ template<std::size_t size, class T> class Vector {
* @see @ref flipped(), @ref Vector2::perpendicular() * @see @ref flipped(), @ref Vector2::perpendicular()
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr 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> constexpr typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif #endif
operator-() const; operator-() const {
return negateInternal(typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/** /**
* @brief Add and assign a vector * @brief Add and assign a vector
@ -381,9 +383,8 @@ 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 { constexpr Vector<size, T> operator+(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return addInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) += other;
} }
/** /**
@ -405,9 +406,8 @@ 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 { constexpr Vector<size, T> operator-(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return subtractInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) -= other;
} }
/** /**
@ -433,9 +433,8 @@ 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*(FloatingPoint) const * @ref operator*(FloatingPoint) const
*/ */
Vector<size, T> operator*(T scalar) const { constexpr Vector<size, T> operator*(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return multiplyInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) *= scalar;
} }
/** /**
@ -443,7 +442,7 @@ template<std::size_t size, class T> class Vector {
* *
* Same as @ref operator*(T) const. * Same as @ref operator*(T) const.
*/ */
friend Vector<size, T> operator*( constexpr friend Vector<size, T> operator*(
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #else
@ -479,13 +478,12 @@ template<std::size_t size, class T> class Vector {
* is done in floating-point. * is done in floating-point.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T> template<class FloatingPoint> constexpr Vector<size, T>
#else #else
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type
#endif #endif
operator*(FloatingPoint scalar) const { operator*(FloatingPoint scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return multiplyIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) *= scalar;
} }
/** /**
@ -498,9 +496,9 @@ template<std::size_t size, class T> class Vector {
which is (and the two don't conflict, apparently, so both are which is (and the two don't conflict, apparently, so both are
present) */ present) */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> friend Vector<size, T> template<class FloatingPoint> friend constexpr Vector<size, T>
#else #else
template<class FloatingPoint, class Integral = T> friend typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type template<class FloatingPoint, class Integral = T> friend constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type
#endif #endif
operator*(FloatingPoint scalar, const Vector<size, T>& vector) { operator*(FloatingPoint scalar, const Vector<size, T>& vector) {
return vector*scalar; return vector*scalar;
@ -529,9 +527,8 @@ 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/(FloatingPoint) const * @ref operator/(FloatingPoint) const
*/ */
Vector<size, T> operator/(T scalar) const { constexpr Vector<size, T> operator/(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return divideInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) /= scalar;
} }
/** /**
@ -542,7 +539,7 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see @ref operator/(T) const * @see @ref operator/(T) const
*/ */
friend Vector<size, T> operator/( friend constexpr Vector<size, T> operator/(
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
T T
#else #else
@ -550,12 +547,7 @@ template<std::size_t size, class T> class Vector {
#endif #endif
scalar, const Vector<size, T>& vector) scalar, const Vector<size, T>& vector)
{ {
Vector<size, T> out; return divideInternal(scalar, vector, typename Containers::Implementation::GenerateSequence<size>::Type{});
for(std::size_t i = 0; i != size; ++i)
out._data[i] = scalar/vector._data[i];
return out;
} }
/** /**
@ -583,13 +575,12 @@ template<std::size_t size, class T> class Vector {
* in floating-point. * in floating-point.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T> template<class FloatingPoint> Vector<size, T> constexpr
#else #else
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type
#endif #endif
operator/(FloatingPoint scalar) const { operator/(FloatingPoint scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return divideIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) /= scalar;
} }
/** /**
@ -615,9 +606,8 @@ template<std::size_t size, class T> class Vector {
* @ref operator*(const Vector<size, FloatingPoint>&) const, * @ref operator*(const Vector<size, FloatingPoint>&) const,
* @ref product() * @ref product()
*/ */
Vector<size, T> operator*(const Vector<size, T>& other) const { constexpr Vector<size, T> operator*(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return multiplyInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) *= other;
} }
/** /**
@ -651,9 +641,8 @@ template<std::size_t size, class T> class Vector {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
, class Integral = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr , class Integral = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr
#endif #endif
> Vector<size, T> operator*(const Vector<size, FloatingPoint>& other) const { > constexpr Vector<size, T> operator*(const Vector<size, FloatingPoint>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return multiplyIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) *= other;
} }
/** /**
@ -670,7 +659,7 @@ template<std::size_t size, class T> class Vector {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
, class FloatingPoint = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr , class FloatingPoint = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr
#endif #endif
> Vector<size, Integral> operator*(const Vector<size, Integral>& other) const { > constexpr Vector<size, Integral> operator*(const Vector<size, Integral>& other) const {
return other**this; return other**this;
} }
@ -696,9 +685,8 @@ 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, FloatingPoint>&) const * @ref operator/(const Vector<size, FloatingPoint>&) const
*/ */
Vector<size, T> operator/(const Vector<size, T>& other) const { constexpr Vector<size, T> operator/(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return divideInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) /= other;
} }
/** /**
@ -729,13 +717,12 @@ template<std::size_t size, class T> class Vector {
* floating-point type to have a floating-point result. * floating-point type to have a floating-point result.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T> template<class FloatingPoint> constexpr Vector<size, T>
#else #else
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, T>>::type
#endif #endif
operator/(const Vector<size, FloatingPoint>& other) const { operator/(const Vector<size, FloatingPoint>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return divideIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) /= other;
} }
/** /**
@ -761,13 +748,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator%(T scalar) const { operator%(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return moduloInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) %= scalar;
} }
/** /**
@ -793,13 +779,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator%(const Vector<size, T>& other) const { operator%(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return moduloInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) %= other;
} }
/** /**
@ -808,17 +793,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator~() const { operator~() const {
Vector<size, T> out; return invertInternal(typename Containers::Implementation::GenerateSequence<size>::Type{});
for(std::size_t i = 0; i != size; ++i)
out._data[i] = ~_data[i];
return out;
} }
/** /**
@ -844,13 +824,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator&(const Vector<size, T>& other) const { operator&(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return andInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) &= other;
} }
/** /**
@ -876,13 +855,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator|(const Vector<size, T>& other) const { operator|(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return orInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) |= other;
} }
/** /**
@ -908,13 +886,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> constexpr Vector<size, T>
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
#endif #endif
operator^(const Vector<size, T>& other) const { operator^(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return xorInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) ^= other;
} }
/** /**
@ -940,14 +917,13 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> operator<<(T shift) const constexpr Vector<size, T> operator<<(T shift) const
#else #else
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type
operator<<(typename std::common_type<T>::type shift) const operator<<(typename std::common_type<T>::type shift) const
#endif #endif
{ {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return shiftLeftInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) <<= shift;
} }
/** /**
@ -973,14 +949,13 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types. * Enabled only for integral types.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> operator>>(T shift) const constexpr Vector<size, T> operator>>(T shift) const
#else #else
template<class Integral = T> template<class Integral = T>
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type operator>>(typename std::common_type<T>::type shift) const constexpr typename std::enable_if<std::is_integral<Integral>::value, Vector<size, T>>::type operator>>(typename std::common_type<T>::type shift) const
#endif #endif
{ {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */ return shiftRightInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{});
return Vector<size, T>(*this) >>= shift;
} }
/** /**
@ -1168,6 +1143,86 @@ template<std::size_t size, class T> class Vector {
builds */ builds */
T _data[size]; T _data[size];
/* Implementation for constexpr operators. Not SFINAE-restricted for
integers or integers + floats, not marked as inline friends, no
std::common_type<T> workarounds for scalars as the callers do all
that already. Protected as they're used directly by subclasses
through the MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION() macro to speed
up debug builds. */
template<std::size_t ...sequence> constexpr Vector<size, T> negateInternal(Containers::Implementation::Sequence<sequence...>) const {
/* All these explicitly cast to T because with e.g. Vector2s it
would otherwise cause narrowing warnings because stupid C
promotion rules make e.g. `short + short` result in an int */
return {T(-_data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> addInternal(const Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] + other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> subtractInternal(const Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] - other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> multiplyInternal(T scalar, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence]*scalar)...};
}
template<std::size_t ...sequence, class FloatingPoint> constexpr Vector<size, T> multiplyIntegerInternal(FloatingPoint scalar, Containers::Implementation::Sequence<sequence...>) const {
/* This has to cast even without C promotion rules in effect, to
convert a floating-point result back to an integer */
return {T(_data[sequence]*scalar)...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> divideInternal(T scalar, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence]/scalar)...};
}
template<std::size_t ...sequence, class FloatingPoint> constexpr Vector<size, T> divideIntegerInternal(FloatingPoint scalar, Containers::Implementation::Sequence<sequence...>) const {
/* This has to cast even without C promotion rules in effect, to
convert a floating-point result back to an integer */
return {T(_data[sequence]/scalar)...};
}
template<std::size_t ...sequence> constexpr static Vector<size, T> divideInternal(T scalar, const Vector<size, T>& vector, Containers::Implementation::Sequence<sequence...>) {
return {T(scalar/vector._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> multiplyInternal(const Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence]*other._data[sequence])...};
}
template<std::size_t ...sequence, class FloatingPoint> constexpr Vector<size, T> multiplyIntegerInternal(const Vector<size, FloatingPoint>& other, Containers::Implementation::Sequence<sequence...>) const {
/* This has to cast even without C promotion rules in effect, to
convert a floating-point result back to an integer */
return {T(_data[sequence]*other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> divideInternal(const Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence]/other._data[sequence])...};
}
template<std::size_t ...sequence, class FloatingPoint> constexpr Vector<size, T> divideIntegerInternal(const Vector<size, FloatingPoint>& other, Containers::Implementation::Sequence<sequence...>) const {
/* This has to cast even without C promotion rules in effect, to
convert a floating-point result back to an integer */
return {T(_data[sequence]/other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> moduloInternal(T scalar, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] % scalar)...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> moduloInternal(const Math::Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] % other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> invertInternal(Containers::Implementation::Sequence<sequence...>) const {
return {T(~_data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> andInternal(const Math::Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] & other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> orInternal(const Math::Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] | other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> xorInternal(const Math::Vector<size, T>& other, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] ^ other._data[sequence])...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> shiftLeftInternal(typename std::common_type<T>::type shift, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] << shift)...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> shiftRightInternal(typename std::common_type<T>::type shift, Containers::Implementation::Sequence<sequence...>) const {
return {T(_data[sequence] >> shift)...};
}
private: private:
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
/* Since I added deprecated aliases to Shaders::VectorGL, this FUCKING /* Since I added deprecated aliases to Shaders::VectorGL, this FUCKING
@ -1270,178 +1325,178 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>&
#endif #endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type) \ #define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type_) \
static Type<T>& from(T* data) { \ static Type_<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \ return *reinterpret_cast<Type_<T>*>(data); \
} \ } \
static const Type<T>& from(const T* data) { \ static const Type_<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \ return *reinterpret_cast<const Type_<T>*>(data); \
} \ } \
template<std::size_t otherSize> constexpr static Type<T> pad(const Math::Vector<otherSize, T>& a, T value = T()) { \ template<std::size_t otherSize> constexpr static Type_<T> pad(const Math::Vector<otherSize, T>& a, T value = T()) { \
return Math::Vector<size, T>::pad(a, value); \ return Math::Vector<size, T>::pad(a, value); \
} \ } \
\ \
constexpr 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> constexpr typename std::enable_if<std::is_signed<U>::value, Type_<T>>::type \
operator-() const { \ operator-() const { \
return Math::Vector<size, T>::operator-(); \ return Math::Vector<size, T>::negateInternal(typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
Type<T>& operator+=(const Math::Vector<size, T>& other) { \ 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>::addInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
Type<T>& operator-=(const Math::Vector<size, T>& other) { \ 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>::subtractInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
\ \
Type<T>& operator*=(T scalar) { \ Type_<T>& operator*=(T scalar) { \
Math::Vector<size, T>::operator*=(scalar); \ Math::Vector<size, T>::operator*=(scalar); \
return *this; \ return *this; \
} \ } \
Type<T> operator*(T scalar) const { \ constexpr Type_<T> operator*(T scalar) const { \
return Math::Vector<size, T>::operator*(scalar); \ return Math::Vector<size, T>::multiplyInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
friend Type<T> operator*(typename std::common_type<T>::type scalar, const Type<T>& vector) { \ friend constexpr Type_<T> operator*(typename std::common_type<T>::type scalar, const Type_<T>& vector) { \
return scalar*static_cast<const Math::Vector<size, T>&>(vector); \ return scalar*static_cast<const Math::Vector<size, T>&>(vector); \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>&>::type operator*=(FloatingPoint scalar) { \ template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>&>::type operator*=(FloatingPoint scalar) { \
Math::Vector<size, T>::operator*=(scalar); \ Math::Vector<size, T>::operator*=(scalar); \
return *this; \ return *this; \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>>::type operator*(FloatingPoint scalar) const { \ template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>>::type operator*(FloatingPoint scalar) const { \
return Math::Vector<size, T>::operator*(scalar); \ return Math::Vector<size, T>::multiplyIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class FloatingPoint, class Integral = T> friend typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>>::type operator*(FloatingPoint scalar, const Type<T>& vector) { \ template<class FloatingPoint, class Integral = T> friend constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>>::type operator*(FloatingPoint scalar, const Type_<T>& vector) { \
return scalar*static_cast<const Math::Vector<size, T>&>(vector); \ return scalar*static_cast<const Math::Vector<size, T>&>(vector); \
} \ } \
\ \
Type<T>& operator/=(T scalar) { \ Type_<T>& operator/=(T scalar) { \
Math::Vector<size, T>::operator/=(scalar); \ Math::Vector<size, T>::operator/=(scalar); \
return *this; \ return *this; \
} \ } \
Type<T> operator/(T scalar) const { \ constexpr Type_<T> operator/(T scalar) const { \
return Math::Vector<size, T>::operator/(scalar); \ return Math::Vector<size, T>::divideInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
friend Type<T> operator/(typename std::common_type<T>::type scalar, const Type<T>& vector) { \ friend constexpr Type_<T> operator/(typename std::common_type<T>::type scalar, const Type_<T>& vector) { \
return scalar/static_cast<const Math::Vector<size, T>&>(vector); \ return scalar/static_cast<const Math::Vector<size, T>&>(vector); \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>&>::type operator/=(FloatingPoint scalar) { \ template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>&>::type operator/=(FloatingPoint scalar) { \
Math::Vector<size, T>::operator/=(scalar); \ Math::Vector<size, T>::operator/=(scalar); \
return *this; \ return *this; \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>>::type operator/(FloatingPoint scalar) const { \ template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>>::type operator/(FloatingPoint scalar) const { \
return Math::Vector<size, T>::operator/(scalar); \ return Math::Vector<size, T>::divideIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
\ \
Type<T>& operator*=(const Math::Vector<size, T>& other) { \ 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>::multiplyInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>&>::type operator*=(const Math::Vector<size, FloatingPoint>& other) { \ template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>&>::type operator*=(const Math::Vector<size, FloatingPoint>& other) { \
Math::Vector<size, T>::operator*=(other); \ Math::Vector<size, T>::operator*=(other); \
return *this; \ return *this; \
} \ } \
template<class FloatingPoint, class Integral = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr> Type<T> operator*(const Math::Vector<size, FloatingPoint>& other) const { \ template<class FloatingPoint, class Integral = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr> constexpr Type_<T> operator*(const Math::Vector<size, FloatingPoint>& other) const { \
return Math::Vector<size, T>::operator*(other); \ return Math::Vector<size, T>::multiplyIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral, class FloatingPoint = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr> Type<Integral> operator*(const Math::Vector<size, Integral>& other) const { \ template<class Integral, class FloatingPoint = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr> constexpr Type_<Integral> operator*(const Math::Vector<size, Integral>& other) const { \
return Math::Vector<size, T>::operator*(other); \ return other**this; \
} \ } \
\ \
Type<T>& operator/=(const Math::Vector<size, T>& other) { \ 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>::divideInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>&>::type operator/=(const Math::Vector<size, FloatingPoint>& other) { \ template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>&>::type operator/=(const Math::Vector<size, FloatingPoint>& other) { \
Math::Vector<size, T>::operator/=(other); \ Math::Vector<size, T>::operator/=(other); \
return *this; \ return *this; \
} \ } \
template<class FloatingPoint, class Integral = T> typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<T>>::type operator/(const Math::Vector<size, FloatingPoint>& other) const { \ template<class FloatingPoint, class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type_<T>>::type operator/(const Math::Vector<size, FloatingPoint>& other) const { \
return Math::Vector<size, T>::operator/(other); \ return Math::Vector<size, T>::divideIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
\ \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator%=(T scalar) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator%=(T scalar) { \
Math::Vector<size, T>::operator%=(scalar); \ Math::Vector<size, T>::operator%=(scalar); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator%(T scalar) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator%(T scalar) const { \
return Math::Vector<size, T>::operator%(scalar); \ return Math::Vector<size, T>::moduloInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator%=(const Math::Vector<size, T>& other) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator%=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator%=(other); \ Math::Vector<size, T>::operator%=(other); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator%(const Math::Vector<size, T>& other) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator%(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator%(other); \ return Math::Vector<size, T>::moduloInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
\ \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator~() const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator~() const { \
return Math::Vector<size, T>::operator~(); \ return Math::Vector<size, T>::invertInternal(typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator&=(const Math::Vector<size, T>& other) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator&=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator&=(other); \ Math::Vector<size, T>::operator&=(other); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator&(const Math::Vector<size, T>& other) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator&(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator&(other); \ return Math::Vector<size, T>::andInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator|=(const Math::Vector<size, T>& other) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator|=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator|=(other); \ Math::Vector<size, T>::operator|=(other); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator|(const Math::Vector<size, T>& other) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator|(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator|(other); \ return Math::Vector<size, T>::orInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator^=(const Math::Vector<size, T>& other) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator^=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator^=(other); \ Math::Vector<size, T>::operator^=(other); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator^(const Math::Vector<size, T>& other) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator^(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator^(other); \ return Math::Vector<size, T>::xorInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator<<=(typename std::common_type<T>::type shift) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator<<=(typename std::common_type<T>::type shift) { \
Math::Vector<size, T>::operator<<=(shift); \ Math::Vector<size, T>::operator<<=(shift); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator<<(typename std::common_type<T>::type shift) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator<<(typename std::common_type<T>::type shift) const { \
return Math::Vector<size, T>::operator<<(shift); \ return Math::Vector<size, T>::shiftLeftInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>&>::type operator>>=(typename std::common_type<T>::type shift) { \ template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type_<T>&>::type operator>>=(typename std::common_type<T>::type shift) { \
Math::Vector<size, T>::operator>>=(shift); \ Math::Vector<size, T>::operator>>=(shift); \
return *this; \ return *this; \
} \ } \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator>>(typename std::common_type<T>::type shift) const { \ template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator>>(typename std::common_type<T>::type shift) const { \
return Math::Vector<size, T>::operator>>(shift); \ return Math::Vector<size, T>::shiftRightInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{}); \
} \ } \
\ \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type normalized() const { \ template<class U = T> 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> 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> 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> 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 { \
return Math::Vector<size, T>::flipped(); \ return Math::Vector<size, T>::flipped(); \
} }
#endif #endif
@ -1455,12 +1510,12 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>&
to return a correct subtype. See VectorTest::multiplyDivideIntegral(), to return a correct subtype. See VectorTest::multiplyDivideIntegral(),
VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test, VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test,
Vector4Test and ColorTest for regression tests. */ Vector4Test and ColorTest for regression tests. */
template<std::size_t size, class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type operator*(FloatingPoint scalar, const Vector<size, Integral>& vector) { template<std::size_t size, class FloatingPoint, class Integral> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type operator*(FloatingPoint scalar, const Vector<size, Integral>& vector) {
return vector*scalar; return vector*scalar;
} }
#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ #define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
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 scalar, const Type<Integral>& vector) { \ template<class FloatingPoint, class Integral> constexpr typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint scalar, const Type<Integral>& vector) { \
return vector*scalar; \ return vector*scalar; \
} }
#endif #endif
@ -1501,21 +1556,6 @@ template<std::size_t size, class T> inline BitVector<size> Vector<size, T>::oper
return out; return out;
} }
template<std::size_t size, class T>
#ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T>
#else
template<class U> inline typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif
Vector<size, T>::operator-() const {
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out._data[i] = -_data[i];
return out;
}
template<std::size_t size, class T> template<std::size_t size, class T>
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T> inline Vector<size, T>

Loading…
Cancel
Save