From 8b1026d457e32357ec18ee2c03c914292a785f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 23 Jan 2024 22:32:01 +0100 Subject: [PATCH] Math: make all matrix and vector operators either member or friend. Except for a vector and a row matrix multiplication operator, which doesn't make sense to be a member. These are all now significantly shorter thanks to not having to repeat that many template parameters, and they can make use of direct access into the _data array for better debug perf. --- src/Magnum/Math/Color.h | 8 - src/Magnum/Math/RectangularMatrix.h | 83 +- src/Magnum/Math/Test/VectorTest.cpp | 2 - src/Magnum/Math/Vector.h | 1123 +++++++++++++-------------- src/Magnum/Math/Vector2.h | 4 - src/Magnum/Math/Vector3.h | 4 - src/Magnum/Math/Vector4.h | 4 - 7 files changed, 584 insertions(+), 644 deletions(-) diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 6eb7327d6..4a59d1f8f 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -715,10 +715,6 @@ template class Color3: public Vector3 { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Color3) }; -#ifndef DOXYGEN_GENERATING_OUTPUT -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3) -#endif - /** @brief Color in linear RGBA color space @@ -1293,10 +1289,6 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const ColorHsv&); #endif #endif -#ifndef DOXYGEN_GENERATING_OUTPUT -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Color4) -#endif - namespace Literals { /** @relatesalso Magnum::Math::Color3 diff --git a/src/Magnum/Math/RectangularMatrix.h b/src/Magnum/Math/RectangularMatrix.h index 55a2472c3..dda34bd42 100644 --- a/src/Magnum/Math/RectangularMatrix.h +++ b/src/Magnum/Math/RectangularMatrix.h @@ -424,6 +424,22 @@ template class RectangularMatrix { return RectangularMatrix(*this) *= scalar; } + /** + * @brief Multiply a scalar with a matrix + * + * Same as @ref operator*(T) const. + */ + friend RectangularMatrix operator*( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + scalar, const RectangularMatrix& matrix) + { + return matrix*scalar; + } + /** * @brief Divide with a scalar and assign * @@ -448,6 +464,30 @@ template class RectangularMatrix { return RectangularMatrix(*this) /= scalar; } + /** + * @brief Divide a matrix with a scalar and invert + * + * The computation is done column-wise. @f[ + * \boldsymbol B_j = \frac a {\boldsymbol A_j} + * @f] + * @see @ref operator/(T) const + */ + friend RectangularMatrix operator/( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + scalar, const RectangularMatrix& matrix) + { + RectangularMatrix out{Magnum::NoInit}; + + for(std::size_t i = 0; i != cols; ++i) + out._data[i] = scalar/matrix._data[i]; + + return out; + } + /** * @brief Multiply a matrix * @@ -637,46 +677,6 @@ Convenience alternative to @cpp RectangularMatrix<4, 3, T> @ce. See template using Matrix4x3 = RectangularMatrix<4, 3, T>; #endif -/** @relates RectangularMatrix -@brief Multiply a scalar with a matrix - -Same as @ref RectangularMatrix::operator*(T) const. -*/ -template inline RectangularMatrix operator*( - #ifdef DOXYGEN_GENERATING_OUTPUT - T - #else - typename std::common_type::type - #endif - scalar, const RectangularMatrix& matrix) -{ - return matrix*scalar; -} - -/** @relates RectangularMatrix -@brief Divide a matrix with a scalar and invert - -The computation is done column-wise. @f[ - \boldsymbol B_j = \frac a {\boldsymbol A_j} -@f] -@see @ref RectangularMatrix::operator/(T) const -*/ -template inline RectangularMatrix operator/( - #ifdef DOXYGEN_GENERATING_OUTPUT - T - #else - typename std::common_type::type - #endif - scalar, const RectangularMatrix& matrix) -{ - RectangularMatrix out{Magnum::NoInit}; - - for(std::size_t i = 0; i != cols; ++i) - out[i] = scalar/matrix[i]; - - return out; -} - /** @relates RectangularMatrix @brief Multiply a vector with a rectangular matrix @@ -785,6 +785,9 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const RectangularMatrix< return Math::RectangularMatrix::flippedRows(); \ } \ +/* Unlike with Vector, these are kept non-member and non-friend as it'd mean + too many macro combinations otherwise */ + #define MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(...) \ template inline __VA_ARGS__ operator*(typename std::common_type::type number, const __VA_ARGS__& matrix) { \ return number*static_cast&>(matrix); \ diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index a182f7954..9fd4c8f7d 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -734,8 +734,6 @@ template class BasicVec2: public Math::Vector<2, T> { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, BasicVec2) }; -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, BasicVec2) - typedef BasicVec2 Vec2; typedef BasicVec2 Vec2i; diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index e608bb966..0ce4d02e5 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -415,7 +415,7 @@ template class Vector { * \boldsymbol a_i = b \boldsymbol a_i * @f] * @see @ref operator*=(const Vector&), - * @ref operator*=(Vector&, FloatingPoint) + * @ref operator*=(FloatingPoint) */ Vector& operator*=(T scalar) { for(std::size_t i = 0; i != size; ++i) @@ -429,12 +429,75 @@ template class Vector { * * @see @ref operator*(const Vector&) const, * @ref operator*=(T), @ref operator*(T, const Vector&), - * @ref operator*(const Vector&, FloatingPoint) + * @ref operator*(FloatingPoint) const */ Vector operator*(T scalar) const { return Vector(*this) *= scalar; } + /** + * @brief Multiply a scalar with a vector + * + * Same as @ref operator*(T) const. + */ + friend Vector operator*( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + scalar, const Vector& vector) + { + return vector*scalar; + } + + /** + * @brief Multiply an integral vector with a floating-point scalar and assign + * + * Similar to @ref operator*=(T), except that the multiplication is + * done in floating-point. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector&>::type + #endif + operator*=(FloatingPoint scalar) { + for(std::size_t i = 0; i != size; ++i) + _data[i] = T(_data[i]*scalar); + + return *this; + } + + /** + * @brief Multiply an integral vector with a floating-point scalar + * + * Similar to @ref operator*(T) const, except that the multiplication + * is done in floating-point. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator*(FloatingPoint scalar) const { + return Vector{*this} *= scalar; + } + + /** + * @brief Multiply a floating-point scalar with an integral vector + * + * Same as @ref operator*(FloatingPoint) const. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template friend Vector + #else + template friend typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator*(FloatingPoint scalar, const Vector& vector) { + return vector*scalar; + } + /** * @brief Divide with a scalar and assign * @@ -442,7 +505,7 @@ template class Vector { * \boldsymbol a_i = \frac{\boldsymbol a_i} b * @f] * @see @ref operator/=(const Vector&), - * @ref operator/=(Vector&, FloatingPoint) + * @ref operator/=(FloatingPoint) */ Vector& operator/=(T scalar) { for(std::size_t i = 0; i != size; ++i) @@ -456,12 +519,69 @@ template class Vector { * * @see @ref operator/(const Vector&) const, * @ref operator/=(T), @ref operator/(T, const Vector&), - * @ref operator/(const Vector&, FloatingPoint) + * @ref operator/(FloatingPoint) const */ Vector operator/(T scalar) const { return Vector(*this) /= scalar; } + /** + * @brief Divide a vector with a scalar and invert + * + * @f[ + * \boldsymbol c_i = \frac b {\boldsymbol a_i} + * @f] + * @see @ref operator/(T) const + */ + friend Vector operator/( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + scalar, const Vector& vector) + { + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out._data[i] = scalar/vector._data[i]; + + return out; + } + + /** + * @brief Divide an integral vector with a floating-point scalar and assign + * + * Similar to @ref operator/=(T), except that the division is done in + * floating-point. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector&>::type + #endif + operator/=(FloatingPoint scalar) { + for(std::size_t i = 0; i != size; ++i) + _data[i] = T(_data[i]/scalar); + + return *this; + } + + /** + * @brief Divide an integral vector with a floating-point scalar + * + * Similar to @ref operator/(T) const, except that the division is done + * in floating-point. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator/(FloatingPoint scalar) const { + return Vector{*this} /= scalar; + } + /** * @brief Multiply a vector component-wise and assign * @@ -469,7 +589,7 @@ template class Vector { * \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i * @f] * @see @ref operator*=(T), - * @ref operator*=(Vector&, const Vector&) + * @ref operator*=(const Vector&) */ Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) @@ -482,13 +602,63 @@ template class Vector { * @brief Multiply a vector component-wise * * @see @ref operator*(T) const, @ref operator*=(const Vector&), - * @ref operator*(const Vector&, const Vector&), + * @ref operator*(const Vector&) const, * @ref product() */ Vector operator*(const Vector& other) const { return Vector(*this) *= other; } + /** + * @brief Multiply an integral vector with a floating-point vector component-wise and assign + * + * Similar to @ref operator*=(const Vector&), except that the + * multiplication is done in floating-point. The computation is done + * in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector&>::type + #endif + operator*=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] = T(_data[i]*other._data[i]); + + return *this; + } + + /** + * @brief Multiply an integral vector with a floating-point vector component-wise + * + * Similar to @ref operator*(const Vector&) const, except that + * the multiplication is done in floating-point. The result is always + * an integral vector, convert both arguments to the same + * floating-point type to have a floating-point result. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator*(const Vector& other) const { + return Vector{*this} *= other; + } + + /** + * @brief Multiply a floating-point vector with an integral vector component-wise + * + * Same as @ref operator*(const Vector&) const. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template friend Vector + #else + template friend typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator*(const Vector& a, const Vector& b) { + return b*a; + } + /** * @brief Divide a vector component-wise and assign * @@ -496,7 +666,7 @@ template class Vector { * \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i} * @f] * @see @ref operator/=(T), - * @ref operator/=(Vector&, const Vector&) + * @ref operator/=(const Vector&) */ Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) @@ -509,12 +679,286 @@ template class Vector { * @brief Divide a vector component-wise * * @see @ref operator/(T) const, @ref operator/=(const Vector&), - * @ref operator/(const Vector&, const Vector&) + * @ref operator/(const Vector&) const */ Vector operator/(const Vector& other) const { return Vector(*this) /= other; } + /** + * @brief Divide an integral vector with a floating-point vector component-wise and assign + * + * Similar to @ref operator/=(const Vector&), except that the + * division is done in floating-point. The computation is done + * in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector&>::type + #endif + operator/=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] = T(_data[i]/other._data[i]); + + return *this; + } + + /** + * @brief Divide an integral vector with a floating-point vector component-wise + * + * Similar to @ref Vector::operator/(const Vector&) const, + * except that the division is done in floating-point. The result is + * always an integral vector, convert both arguments to the same + * floating-point type to have a floating-point result. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector + #else + template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + #endif + operator/(const Vector& other) const { + return Vector{*this} /= other; + } + + /** + * @brief Do modulo of a vector and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& + #else + template typename std::enable_if::value, Vector&>::type + #endif + operator%=(T other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] %= other; + + return *this; + } + + /** + * @brief Modulo of a vector + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator%(T scalar) const { + return Vector{*this} %= scalar; + } + + /** + * @brief Do modulo of two vectors and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& + #else + template typename std::enable_if::value, Vector&>::type + #endif + operator%=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] %= other._data[i]; + + return *this; + } + + /** + * @brief Modulo of two vectors + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator%(const Vector& other) const { + return Vector{*this} %= other; + } + + /** + * @brief Bitwise NOT of a vector + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator~() const { + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out._data[i] = ~_data[i]; + + return out; + } + + /** + * @brief Do bitwise AND of two vectors and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& + #else + template typename std::enable_if::value, Vector&>::type + #endif + operator&=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] &= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise AND of two vectors + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator&(const Vector& other) const { + return Vector{*this} &= other; + } + + /** + * @brief Do bitwise OR of two vectors and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& + #else + template typename std::enable_if::value, Vector&>::type + #endif + operator|=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] |= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise OR of two vectors + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator|(const Vector& other) const { + return Vector{*this} |= other; + } + + /** + * @brief Do bitwise XOR of two vectors and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& + #else + template typename std::enable_if::value, Vector&>::type + #endif + operator^=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] ^= other._data[i]; + + return *this; + } + + /** + * @brief Bitwise XOR of two vectors + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector + #else + template typename std::enable_if::value, Vector>::type + #endif + operator^(const Vector& other) const { + return Vector{*this} ^= other; + } + + /** + * @brief Do bitwise left shift of a vector and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& operator<<=(T shift) + #else + template typename std::enable_if::value, Vector&>::type operator<<=(typename std::common_type::type shift) + #endif + { + for(std::size_t i = 0; i != size; ++i) + _data[i] <<= shift; + + return *this; + } + + /** + * @brief Bitwise left shift of a vector + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector operator<<(T shift) const + #else + template typename std::enable_if::value, Vector>::type + operator<<(typename std::common_type::type shift) const + #endif + { + return Vector{*this} <<= shift; + } + + /** + * @brief Do bitwise right shift of a vector and assign + * + * Enabled only for integral types. The computation is done in-place. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector& operator>>=(T shift) + #else + template typename std::enable_if::value, Vector&>::type operator>>=(typename std::common_type::type shift) + #endif + { + for(std::size_t i = 0; i != size; ++i) + _data[i] >>= shift; + + return *this; + } + + /** + * @brief Bitwise left shift of a vector + * + * Enabled only for integral types. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector operator>>(T shift) const + #else + template + typename std::enable_if::value, Vector>::type operator>>(typename std::common_type::type shift) const + #endif + { + return Vector{*this} >>= shift; + } + /** * @brief Dot product of the vector * @@ -770,492 +1214,6 @@ template inline BitVector notEqual(const Vector return out; } -/** @relates Vector -@brief Multiply a scalar with a vector - -Same as @ref Vector::operator*(T) const. -*/ -template inline Vector operator*( - #ifdef DOXYGEN_GENERATING_OUTPUT - T - #else - typename std::common_type::type - #endif - scalar, const Vector& vector) -{ - return vector*scalar; -} - -/** @relates Vector -@brief Divide a vector with a scalar and invert - -@f[ - \boldsymbol c_i = \frac b {\boldsymbol a_i} -@f] -@see @ref Vector::operator/(T) const -*/ -template inline Vector operator/( - #ifdef DOXYGEN_GENERATING_OUTPUT - T - #else - typename std::common_type::type - #endif - scalar, const Vector& vector) -{ - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out[i] = scalar/vector[i]; - - return out; -} - -/** @relates Vector -@brief Do modulo of an integral vector and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator%=(Vector& a, Integral b) { - for(std::size_t i = 0; i != size; ++i) - a[i] %= b; - - return a; -} - -/** @relates Vector -@brief Modulo of an integral vector -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator%(const Vector& a, Integral b) { - Vector copy(a); - return copy %= b; -} - -/** @relates Vector -@brief Do modulo of two integral vectors and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator%=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] %= b[i]; - - return a; -} - -/** @relates Vector -@brief Modulo of two integral vectors -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator%(const Vector& a, const Vector& b) { - Vector copy(a); - return copy %= b; -} - -/** @relates Vector -@brief Bitwise NOT of an integral vector -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator~(const Vector& vector) { - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out[i] = ~vector[i]; - - return out; -} - -/** @relates Vector -@brief Do bitwise AND of two integral vectors and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator&=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] &= b[i]; - - return a; -} - -/** @relates Vector -@brief Bitwise AND of two integral vectors -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator&(const Vector& a, const Vector& b) { - Vector copy(a); - return copy &= b; -} - -/** @relates Vector -@brief Do bitwise OR of two integral vectors and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator|=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] |= b[i]; - - return a; -} - -/** @relates Vector -@brief Bitwise OR of two integral vectors -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator|(const Vector& a, const Vector& b) { - Vector copy(a); - return copy |= b; -} - -/** @relates Vector -@brief Do bitwise XOR of two integral vectors and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator^=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] ^= b[i]; - - return a; -} - -/** @relates Vector -@brief Bitwise XOR of two integral vectors -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator^(const Vector& a, const Vector& b) { - Vector copy(a); - return copy ^= b; -} - -/** @relates Vector -@brief Do bitwise left shift of an integral vector and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator<<=(Vector& vector, - #ifdef DOXYGEN_GENERATING_OUTPUT - Integral - #else - typename std::common_type::type - #endif - shift) -{ - for(std::size_t i = 0; i != size; ++i) - vector[i] <<= shift; - - return vector; -} - -/** @relates Vector -@brief Bitwise left shift of an integral vector -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator<<(const Vector& vector, - #ifdef DOXYGEN_GENERATING_OUTPUT - Integral - #else - typename std::common_type::type - #endif - shift) -{ - Vector copy(vector); - return copy <<= shift; -} - -/** @relates Vector -@brief Do bitwise right shift of an integral vector and assign - -The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value, Vector&>::type -#endif -operator>>=(Vector& vector, - #ifdef DOXYGEN_GENERATING_OUTPUT - Integral - #else - typename std::common_type::type - #endif - shift) { - for(std::size_t i = 0; i != size; ++i) - vector[i] >>= shift; - - return vector; -} - -/** @relates Vector -@brief Bitwise left shift of an integral vector -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value, Vector>::type -#endif -operator>>(const Vector& vector, - #ifdef DOXYGEN_GENERATING_OUTPUT - Integral - #else - typename std::common_type::type - #endif - shift) { - Vector copy(vector); - return copy >>= shift; -} - -/** @relates Vector -@brief Multiply an integral vector with a floating-point scalar and assign - -Similar to @ref Vector::operator*=(T), except that the multiplication is done -in floating-point. The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value && std::is_floating_point::value, Vector&>::type -#endif -operator*=(Vector& vector, FloatingPoint scalar) { - for(std::size_t i = 0; i != size; ++i) - vector[i] = Integral(vector[i]*scalar); - - return vector; -} - -/** @relates Vector -@brief Multiply an integral vector with a floating-point scalar - -Similar to @ref Vector::operator*(T) const, except that the multiplication is -done in floating-point. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator*(const Vector& vector, FloatingPoint scalar) { - Vector copy(vector); - return copy *= scalar; -} - -/** @relates Vector -@brief Multiply a floating-point scalar with an integral vector - -Same as @ref operator*(const Vector&, FloatingPoint). -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator*(FloatingPoint scalar, const Vector& vector) { - return vector*scalar; -} - -/** @relates Vector -@brief Divide an integral vector with a floating-point scalar and assign - -Similar to @ref Vector::operator/=(T), except that the division is done in -floating-point. The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value && std::is_floating_point::value, Vector&>::type -#endif -operator/=(Vector& vector, FloatingPoint scalar) { - for(std::size_t i = 0; i != size; ++i) - vector[i] = Integral(vector[i]/scalar); - - return vector; -} - -/** @relates Vector -@brief Divide an integral vector with a floating-point scalar - -Similar to @ref Vector::operator/(T) const, except that the division is done in -floating-point. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator/(const Vector& vector, FloatingPoint scalar) { - Vector copy(vector); - return copy /= scalar; -} - -/** @relates Vector -@brief Multiply an integral vector with a floating-point vector component-wise and assign - -Similar to @ref Vector::operator*=(const Vector&), except that the -multiplication is done in floating-point. The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value && std::is_floating_point::value, Vector&>::type -#endif -operator*=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] = Integral(a[i]*b[i]); - - return a; -} - -/** @relates Vector -@brief Multiply an integral vector with a floating-point vector component-wise - -Similar to @ref Vector::operator*(const Vector&) const, except that -the multiplication is done in floating-point. The result is always integral -vector, convert both arguments to the same floating-point type to have -floating-point result. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator*(const Vector& a, const Vector& b) { - Vector copy(a); - return copy *= b; -} - -/** @relates Vector -@brief Multiply a floating-point vector with an integral vector component-wise - -Same as @ref operator*(const Vector&, const Vector&). -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator*(const Vector& a, const Vector& b) { - return b*a; -} - -/** @relates Vector -@brief Divide an integral vector with a floating-point vector component-wise and assign - -Similar to @ref Vector::operator/=(const Vector&), except that the -division is done in floating-point. The computation is done in-place. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector& -#else -typename std::enable_if::value && std::is_floating_point::value, Vector&>::type -#endif -operator/=(Vector& a, const Vector& b) { - for(std::size_t i = 0; i != size; ++i) - a[i] = Integral(a[i]/b[i]); - - return a; -} - -/** @relates Vector -@brief Divide an integral vector with a floating-point vector component-wise - -Similar to @ref Vector::operator/(const Vector&) const, except that -the division is done in floating-point. The result is always integral vector, -convert both arguments to the same floating-point type to have floating-point -result. -*/ -template inline -#ifdef DOXYGEN_GENERATING_OUTPUT -Vector -#else -typename std::enable_if::value && std::is_floating_point::value, Vector>::type -#endif -operator/(const Vector& a, const Vector& b) { - Vector copy(a); - return copy /= b; -} - #ifndef CORRADE_SINGLES_NO_DEBUG /** @debugoperator{Vector} */ template Debug& operator<<(Debug& debug, const Vector& value) { @@ -1320,6 +1278,7 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& Type operator-(const Math::Vector& other) const { \ return Math::Vector::operator-(other); \ } \ + \ Type& operator*=(T scalar) { \ Math::Vector::operator*=(scalar); \ return *this; \ @@ -1327,6 +1286,20 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& Type operator*(T scalar) const { \ return Math::Vector::operator*(scalar); \ } \ + friend Type operator*(typename std::common_type::type scalar, const Type& vector) { \ + return scalar*static_cast&>(vector); \ + } \ + template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(FloatingPoint scalar) { \ + Math::Vector::operator*=(scalar); \ + return *this; \ + } \ + template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar) const { \ + return Math::Vector::operator*(scalar); \ + } \ + template friend typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ + return scalar*static_cast&>(vector); \ + } \ + \ Type& operator/=(T scalar) { \ Math::Vector::operator/=(scalar); \ return *this; \ @@ -1334,6 +1307,17 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& Type operator/(T scalar) const { \ return Math::Vector::operator/(scalar); \ } \ + friend Type operator/(typename std::common_type::type scalar, const Type& vector) { \ + return scalar/static_cast&>(vector); \ + } \ + template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(FloatingPoint scalar) { \ + Math::Vector::operator/=(scalar); \ + return *this; \ + } \ + template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(FloatingPoint scalar) const { \ + return Math::Vector::operator/(scalar); \ + } \ + \ Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ @@ -1341,6 +1325,17 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& Type operator*(const Math::Vector& other) const { \ return Math::Vector::operator*(other); \ } \ + template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(const Math::Vector& other) { \ + Math::Vector::operator*=(other); \ + return *this; \ + } \ + template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Math::Vector& other) const { \ + return Math::Vector::operator*(other); \ + } \ + template friend typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Math::Vector& a, const Type& b) { \ + return a*static_cast&>(b); \ + } \ + \ Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ @@ -1348,118 +1343,82 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& Type operator/(const Math::Vector& other) const { \ return Math::Vector::operator/(other); \ } \ - \ - template typename std::enable_if::value, Type>::type normalized() const { \ - return Math::Vector::normalized(); \ - } \ - template typename std::enable_if::value, Type>::type resized(T length) const { \ - return Math::Vector::resized(length); \ - } \ - template typename std::enable_if::value, Type>::type projected(const Math::Vector& other) const { \ - return Math::Vector::projected(other); \ - } \ - template typename std::enable_if::value, Type>::type projectedOntoNormalized(const Math::Vector& other) const { \ - return Math::Vector::projectedOntoNormalized(other); \ - } \ - constexpr Type flipped() const { \ - return Math::Vector::flipped(); \ - } - -#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ - template inline Type operator*(typename std::common_type::type scalar, const Type& vector) { \ - return scalar*static_cast&>(vector); \ + template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(const Math::Vector& other) { \ + Math::Vector::operator/=(other); \ + return *this; \ } \ - template inline Type operator/(typename std::common_type::type scalar, const Type& vector) { \ - return scalar/static_cast&>(vector); \ + template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Math::Vector& other) const { \ + return Math::Vector::operator/(other); \ } \ \ - template inline typename std::enable_if::value, Type&>::type operator%=(Type& a, Integral b) { \ - static_cast&>(a) %= b; \ - return a; \ + template typename std::enable_if::value, Type&>::type operator%=(T scalar) { \ + Math::Vector::operator%=(scalar); \ + return *this; \ } \ - template inline typename std::enable_if::value, Type>::type operator%(const Type& a, Integral b) { \ - return static_cast&>(a) % b; \ + template typename std::enable_if::value, Type>::type operator%(T scalar) const { \ + return Math::Vector::operator%(scalar); \ } \ - template inline typename std::enable_if::value, Type&>::type operator%=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) %= b; \ - return a; \ + template typename std::enable_if::value, Type&>::type operator%=(const Math::Vector& other) { \ + Math::Vector::operator%=(other); \ + return *this; \ } \ - template inline typename std::enable_if::value, Type>::type operator%(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) % b; \ + template typename std::enable_if::value, Type>::type operator%(const Math::Vector& other) const { \ + return Math::Vector::operator%(other); \ } \ \ - template inline typename std::enable_if::value, Type>::type operator~(const Type& vector) { \ - return ~static_cast&>(vector); \ - } \ - template inline typename std::enable_if::value, Type&>::type operator&=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) &= b; \ - return a; \ - } \ - template inline typename std::enable_if::value, Type>::type operator&(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) & b; \ - } \ - template inline typename std::enable_if::value, Type&>::type operator|=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) |= b; \ - return a; \ + template typename std::enable_if::value, Type>::type operator~() const { \ + return Math::Vector::operator~(); \ } \ - template inline typename std::enable_if::value, Type>::type operator|(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) | b; \ - } \ - template inline typename std::enable_if::value, Type&>::type operator^=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) ^= b; \ - return a; \ - } \ - template inline typename std::enable_if::value, Type>::type operator^(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) ^ b; \ + template typename std::enable_if::value, Type&>::type operator&=(const Math::Vector& other) { \ + Math::Vector::operator&=(other); \ + return *this; \ } \ - template inline typename std::enable_if::value, Type&>::type operator<<=(Type& vector, typename std::common_type::type shift) { \ - static_cast&>(vector) <<= shift; \ - return vector; \ + template typename std::enable_if::value, Type>::type operator&(const Math::Vector& other) const { \ + return Math::Vector::operator&(other); \ } \ - template inline typename std::enable_if::value, Type>::type operator<<(const Type& vector, typename std::common_type::type shift) { \ - return static_cast&>(vector) << shift; \ + template typename std::enable_if::value, Type&>::type operator|=(const Math::Vector& other) { \ + Math::Vector::operator|=(other); \ + return *this; \ } \ - template inline typename std::enable_if::value, Type&>::type operator>>=(Type& vector, typename std::common_type::type shift) { \ - static_cast&>(vector) >>= shift; \ - return vector; \ + template typename std::enable_if::value, Type>::type operator|(const Math::Vector& other) const { \ + return Math::Vector::operator|(other); \ } \ - template inline typename std::enable_if::value, Type>::type operator>>(const Type& vector, typename std::common_type::type shift) { \ - return static_cast&>(vector) >> shift; \ + template typename std::enable_if::value, Type&>::type operator^=(const Math::Vector& other) { \ + Math::Vector::operator^=(other); \ + return *this; \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& vector, FloatingPoint scalar) { \ - static_cast&>(vector) *= scalar; \ - return vector; \ + template typename std::enable_if::value, Type>::type operator^(const Math::Vector& other) const { \ + return Math::Vector::operator^(other); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& vector, FloatingPoint scalar) { \ - return static_cast&>(vector)*scalar; \ + template typename std::enable_if::value, Type&>::type operator<<=(typename std::common_type::type shift) { \ + Math::Vector::operator<<=(shift); \ + return *this; \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ - return scalar*static_cast&>(vector); \ + template typename std::enable_if::value, Type>::type operator<<(typename std::common_type::type shift) const { \ + return Math::Vector::operator<<(shift); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& vector, FloatingPoint scalar) { \ - static_cast&>(vector) /= scalar; \ - return vector; \ + template typename std::enable_if::value, Type&>::type operator>>=(typename std::common_type::type shift) { \ + Math::Vector::operator>>=(shift); \ + return *this; \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& vector, FloatingPoint scalar) { \ - return static_cast&>(vector)/scalar; \ + template typename std::enable_if::value, Type>::type operator>>(typename std::common_type::type shift) const { \ + return Math::Vector::operator>>(shift); \ } \ \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) *= b; \ - return a; \ + template typename std::enable_if::value, Type>::type normalized() const { \ + return Math::Vector::normalized(); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a)*b; \ + template typename std::enable_if::value, Type>::type resized(T length) const { \ + return Math::Vector::resized(length); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Math::Vector& a, const Type& b) { \ - return a*static_cast&>(b); \ + template typename std::enable_if::value, Type>::type projected(const Math::Vector& other) const { \ + return Math::Vector::projected(other); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) /= b; \ - return a; \ + template typename std::enable_if::value, Type>::type projectedOntoNormalized(const Math::Vector& other) const { \ + return Math::Vector::projectedOntoNormalized(other); \ } \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a)/b; \ + constexpr Type flipped() const { \ + return Math::Vector::flipped(); \ } #endif diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index 452c35214..7162e2d47 100644 --- a/src/Magnum/Math/Vector2.h +++ b/src/Magnum/Math/Vector2.h @@ -235,10 +235,6 @@ template class Vector2: public Vector<2, T> { template friend U cross(const Vector2&, const Vector2&); }; -#ifndef DOXYGEN_GENERATING_OUTPUT -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, Vector2) -#endif - namespace Implementation { template struct TypeForSize; template struct TypeForSize<2, T> { typedef Math::Vector2 Type; }; diff --git a/src/Magnum/Math/Vector3.h b/src/Magnum/Math/Vector3.h index 3b44d4d2b..3cea7e3d2 100644 --- a/src/Magnum/Math/Vector3.h +++ b/src/Magnum/Math/Vector3.h @@ -262,10 +262,6 @@ template class Vector3: public Vector<3, T> { template friend Vector3 cross(const Vector3&, const Vector3&); }; -#ifndef DOXYGEN_GENERATING_OUTPUT -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Vector3) -#endif - #ifndef MAGNUM_NO_MATH_STRICT_WEAK_ORDERING namespace Implementation { template struct TypeForSize<3, T> { typedef Math::Vector3 Type; }; diff --git a/src/Magnum/Math/Vector4.h b/src/Magnum/Math/Vector4.h index 40efff750..5e827f7c9 100644 --- a/src/Magnum/Math/Vector4.h +++ b/src/Magnum/Math/Vector4.h @@ -284,10 +284,6 @@ template Vector4 planeEquation(const Vector3& normal, const Vecto return {normal, -Math::dot(normal, point)}; } -#ifndef DOXYGEN_GENERATING_OUTPUT -MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4) -#endif - #ifndef MAGNUM_NO_MATH_STRICT_WEAK_ORDERING namespace Implementation { template struct TypeForSize<4, T> { typedef Math::Vector4 Type; };