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 */
CORRADE_COMPARE(-1.5f*vector3, multiplied3);
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() {

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
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
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() {

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
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
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() {

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
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
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() {

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 promotedA = +a;
constexpr Vector4 negatedA = -a;
CORRADE_COMPARE(promotedA, a);
CORRADE_COMPARE(negatedA, (Vector4{-1.0f, 3.0f, -5.0f, 10.0f}));
}
void VectorTest::addSubtract() {
@ -426,6 +428,15 @@ void VectorTest::addSubtract() {
CORRADE_COMPARE(&(v -= b), &v);
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() {
@ -447,10 +458,24 @@ void VectorTest::multiplyDivide() {
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 */
const Vector4 divisor{1.0f, 2.0f, -4.0f, 8.0f};
const Vector4 result{1.0f, 0.5f, -0.25f, 0.125f};
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() {
@ -472,6 +497,16 @@ void VectorTest::multiplyDivideIntegral() {
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 */
}
@ -493,6 +528,14 @@ void VectorTest::multiplyDivideComponentWise() {
CORRADE_COMPARE(&(v /= multiplier), &v);
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() {
@ -515,6 +558,17 @@ void VectorTest::multiplyDivideComponentWiseIntegral() {
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 */
}
@ -535,6 +589,13 @@ void VectorTest::modulo() {
CORRADE_COMPARE(&(v %= b), &v);
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() {
@ -563,6 +624,17 @@ void VectorTest::bitwise() {
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};
CORRADE_COMPARE(c << 2, (Vector4i{28, 128, 4, 60}));
{
@ -577,6 +649,12 @@ void VectorTest::bitwise() {
CORRADE_COMPARE(&(v >>= 2), &v);
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() {
@ -855,6 +933,11 @@ void VectorTest::subclass() {
}
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 */
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};
CORRADE_COMPARE(&(a += Vec2{1.0f, -3.0f}), &a);
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));
@ -869,6 +957,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a -= Vec2{1.0f, -3.0f}), &a);
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 */
@ -878,6 +971,12 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a *= 2.0f), &a);
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));
@ -886,6 +985,12 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a /= 0.5f), &a);
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 */
@ -895,6 +1000,12 @@ void VectorTest::subclass() {
Vec2i a{2, 4};
CORRADE_COMPARE(&(a *= 1.5f), &a);
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};
CORRADE_COMPARE(&(a /= (2.0f/3.0f)), &a);
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 */
@ -915,6 +1030,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a *= Vec2{1.5f, -2.0f}), &a);
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));
@ -922,6 +1042,11 @@ void VectorTest::subclass() {
Vec2 a{-2.0f, 5.0f};
CORRADE_COMPARE(&(a /= Vec2{2.0f/3.0f, -0.5f}), &a);
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 */
@ -931,6 +1056,13 @@ void VectorTest::subclass() {
Vec2i a{2, 4};
CORRADE_COMPARE(&(a *= Vec2{-1.5f, 0.5f}), &a);
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};
CORRADE_COMPARE(&(a /= Vec2{-2.0f/3.0f, 2.0f}), &a);
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 */
@ -951,6 +1088,10 @@ void VectorTest::subclass() {
Vec2i a{4, 13};
CORRADE_COMPARE(&(a %= 2), &a);
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));
@ -958,10 +1099,20 @@ void VectorTest::subclass() {
Vec2i a{4, 13};
CORRADE_COMPARE(&(a %= Vec2i{2, 5}), &a);
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 */
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 */
CORRADE_COMPARE(Vec2i(85, 240) & Vec2i(170, 85), Vec2i(0, 80));
@ -969,6 +1120,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240};
CORRADE_COMPARE(&(a &= Vec2i{170, 85}), &a);
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));
@ -976,6 +1132,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240};
CORRADE_COMPARE(&(a |= Vec2i{170, 85}), &a);
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));
@ -983,6 +1144,11 @@ void VectorTest::subclass() {
Vec2i a{85, 240};
CORRADE_COMPARE(&(a ^= Vec2i{170, 85}), &a);
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 */
@ -991,6 +1157,10 @@ void VectorTest::subclass() {
Vec2i a{7, 32};
CORRADE_COMPARE(&(a <<= 2), &a);
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));
@ -998,6 +1168,10 @@ void VectorTest::subclass() {
Vec2i a{7, 32};
CORRADE_COMPARE(&(a >>= 2), &a);
CORRADE_COMPARE(a, (Vec2i{1, 8}));
constexpr Vec2i ca{7, 32};
constexpr Vec2i cb = ca >> 2;
CORRADE_COMPARE(cb, (Vec2i{1, 8}));
}
/* 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()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
template<class U = T> constexpr typename std::enable_if<std::is_signed<U>::value, Vector<size, T>>::type
#endif
operator-() const;
operator-() const {
return negateInternal(typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
* @brief Add and assign a vector
@ -381,9 +383,8 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref operator+=(), @ref sum()
*/
Vector<size, T> operator+(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) += other;
constexpr Vector<size, T> operator+(const Vector<size, T>& other) const {
return addInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -405,9 +406,8 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref operator-=()
*/
Vector<size, T> operator-(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) -= other;
constexpr Vector<size, T> operator-(const Vector<size, T>& other) const {
return subtractInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -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*(FloatingPoint) const
*/
Vector<size, T> operator*(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) *= scalar;
constexpr Vector<size, T> operator*(T scalar) const {
return multiplyInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -443,7 +442,7 @@ template<std::size_t size, class T> class Vector {
*
* Same as @ref operator*(T) const.
*/
friend Vector<size, T> operator*(
constexpr friend Vector<size, T> operator*(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
@ -479,13 +478,12 @@ template<std::size_t size, class T> class Vector {
* is done in floating-point.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T>
template<class FloatingPoint> constexpr Vector<size, T>
#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
operator*(FloatingPoint scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) *= scalar;
return multiplyIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -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
present) */
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> friend Vector<size, T>
template<class FloatingPoint> friend constexpr Vector<size, T>
#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
operator*(FloatingPoint scalar, const Vector<size, T>& vector) {
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/(FloatingPoint) const
*/
Vector<size, T> operator/(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) /= scalar;
constexpr Vector<size, T> operator/(T scalar) const {
return divideInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -542,7 +539,7 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see @ref operator/(T) const
*/
friend Vector<size, T> operator/(
friend constexpr Vector<size, T> operator/(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
@ -550,12 +547,7 @@ template<std::size_t size, class T> class Vector {
#endif
scalar, const Vector<size, T>& vector)
{
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out._data[i] = scalar/vector._data[i];
return out;
return divideInternal(scalar, vector, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -583,13 +575,12 @@ template<std::size_t size, class T> class Vector {
* in floating-point.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T>
template<class FloatingPoint> Vector<size, T> constexpr
#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
operator/(FloatingPoint scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) /= scalar;
return divideIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -615,9 +606,8 @@ template<std::size_t size, class T> class Vector {
* @ref operator*(const Vector<size, FloatingPoint>&) const,
* @ref product()
*/
Vector<size, T> operator*(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) *= other;
constexpr Vector<size, T> operator*(const Vector<size, T>& other) const {
return multiplyInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -651,9 +641,8 @@ template<std::size_t size, class T> class Vector {
#ifndef DOXYGEN_GENERATING_OUTPUT
, class Integral = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr
#endif
> Vector<size, T> operator*(const Vector<size, FloatingPoint>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) *= other;
> constexpr Vector<size, T> operator*(const Vector<size, FloatingPoint>& other) const {
return multiplyIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -670,7 +659,7 @@ template<std::size_t size, class T> class Vector {
#ifndef DOXYGEN_GENERATING_OUTPUT
, class FloatingPoint = T, typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value>::type* = nullptr
#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;
}
@ -696,9 +685,8 @@ template<std::size_t size, class T> class Vector {
* @see @ref operator/(T) const, @ref operator/=(const Vector<size, T>&),
* @ref operator/(const Vector<size, FloatingPoint>&) const
*/
Vector<size, T> operator/(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) /= other;
constexpr Vector<size, T> operator/(const Vector<size, T>& other) const {
return divideInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -729,13 +717,12 @@ template<std::size_t size, class T> class Vector {
* floating-point type to have a floating-point result.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> Vector<size, T>
template<class FloatingPoint> constexpr Vector<size, T>
#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
operator/(const Vector<size, FloatingPoint>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) /= other;
return divideIntegerInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -761,13 +748,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator%(T scalar) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) %= scalar;
return moduloInternal(scalar, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -793,13 +779,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator%(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) %= other;
return moduloInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -808,17 +793,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator~() const {
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out._data[i] = ~_data[i];
return out;
return invertInternal(typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -844,13 +824,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator&(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) &= other;
return andInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -876,13 +855,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator|(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) |= other;
return orInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -908,13 +886,12 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
constexpr Vector<size, T>
#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
operator^(const Vector<size, T>& other) const {
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) ^= other;
return xorInternal(other, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -940,14 +917,13 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> operator<<(T shift) const
constexpr Vector<size, T> operator<<(T shift) const
#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
#endif
{
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) <<= shift;
return shiftLeftInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -973,14 +949,13 @@ template<std::size_t size, class T> class Vector {
* Enabled only for integral types.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T> operator>>(T shift) const
constexpr Vector<size, T> operator>>(T shift) const
#else
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
{
/* MSVC 2015 and 2017 treat the copy as a const if {} is used */
return Vector<size, T>(*this) >>= shift;
return shiftRightInternal(shift, typename Containers::Implementation::GenerateSequence<size>::Type{});
}
/**
@ -1168,6 +1143,86 @@ template<std::size_t size, class T> class Vector {
builds */
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:
#ifndef DOXYGEN_GENERATING_OUTPUT
/* 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
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type) \
static Type<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type_) \
static Type_<T>& from(T* data) { \
return *reinterpret_cast<Type_<T>*>(data); \
} \
static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \
static const Type_<T>& from(const 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); \
} \
\
constexpr Type<T> operator+() const { \
constexpr Type_<T> operator+() const { \
return Math::Vector<size, T>::operator+(); \
} \
template<class U = T> typename std::enable_if<std::is_signed<U>::value, Type<T>>::type \
template<class U = T> constexpr typename std::enable_if<std::is_signed<U>::value, Type_<T>>::type \
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); \
return *this; \
} \
Type<T> operator+(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator+(other); \
constexpr Type_<T> operator+(const Math::Vector<size, T>& other) const { \
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); \
return *this; \
} \
Type<T> operator-(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator-(other); \
constexpr Type_<T> operator-(const Math::Vector<size, T>& other) const { \
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); \
return *this; \
} \
Type<T> operator*(T scalar) const { \
return Math::Vector<size, T>::operator*(scalar); \
constexpr Type_<T> operator*(T scalar) const { \
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); \
} \
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); \
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 { \
return Math::Vector<size, T>::operator*(scalar); \
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>::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); \
} \
\
Type<T>& operator/=(T scalar) { \
Type_<T>& operator/=(T scalar) { \
Math::Vector<size, T>::operator/=(scalar); \
return *this; \
} \
Type<T> operator/(T scalar) const { \
return Math::Vector<size, T>::operator/(scalar); \
constexpr Type_<T> operator/(T scalar) const { \
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); \
} \
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); \
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 { \
return Math::Vector<size, T>::operator/(scalar); \
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>::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); \
return *this; \
} \
Type<T> operator*(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \
constexpr Type_<T> operator*(const Math::Vector<size, T>& other) const { \
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); \
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 { \
return Math::Vector<size, T>::operator*(other); \
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>::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 { \
return Math::Vector<size, T>::operator*(other); \
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 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); \
return *this; \
} \
Type<T> operator/(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator/(other); \
constexpr Type_<T> operator/(const Math::Vector<size, T>& other) const { \
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); \
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 { \
return Math::Vector<size, T>::operator/(other); \
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>::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); \
return *this; \
} \
template<class Integral = T> typename std::enable_if<std::is_integral<Integral>::value, Type<T>>::type operator%(T scalar) const { \
return Math::Vector<size, T>::operator%(scalar); \
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>::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); \
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 { \
return Math::Vector<size, T>::operator%(other); \
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>::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 { \
return Math::Vector<size, T>::operator~(); \
template<class Integral = T> constexpr typename std::enable_if<std::is_integral<Integral>::value, Type_<T>>::type operator~() const { \
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); \
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 { \
return Math::Vector<size, T>::operator&(other); \
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>::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); \
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 { \
return Math::Vector<size, T>::operator|(other); \
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>::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); \
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 { \
return Math::Vector<size, T>::operator^(other); \
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>::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); \
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 { \
return Math::Vector<size, T>::operator<<(shift); \
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>::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); \
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 { \
return Math::Vector<size, T>::operator>>(shift); \
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>::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(); \
} \
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); \
} \
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); \
} \
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); \
} \
constexpr Type<T> flipped() const { \
constexpr Type_<T> flipped() const { \
return Math::Vector<size, T>::flipped(); \
}
#endif
@ -1455,12 +1510,12 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>&
to return a correct subtype. See VectorTest::multiplyDivideIntegral(),
VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test,
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;
}
#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; \
}
#endif
@ -1501,21 +1556,6 @@ template<std::size_t size, class T> inline BitVector<size> Vector<size, T>::oper
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>
#ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T>

Loading…
Cancel
Save