diff --git a/doc/changelog.dox b/doc/changelog.dox index 963a4401d..f77184d27 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -272,6 +272,9 @@ See also: flip of various block-compressed formats - New @ref Math::Nanoseconds and @ref Math::Seconds classes for strongly typed representation of time values +- @ref Math::Vector, @ref Math::RectangularMatrix and all their subclasses + can be now constructed from fixed-size arrays without having to use the + potentially dangerous and non-constexpr @ref Math::Vector::from() API @subsubsection changelog-latest-new-materialtools MaterialTools library diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 83c21d581..5fe53f37b 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -561,6 +561,14 @@ template class Color3: public Vector3 { */ constexpr /*implicit*/ Color3(const Vector<2, T>& rg, T b) noexcept: Vector3{rg, b} {} + /** @copydoc Vector::Vector(const T(&)[size_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Color3(const T(&data)[size_]) noexcept: Vector3{data} {} + #else + /* GCC 4.8 workaround, see the Vector base for details */ + constexpr explicit Color3(const T(&data)[3]) noexcept: Vector3{data} {} + #endif + /** * @copydoc Vector::Vector(const Vector&) * @@ -1049,6 +1057,14 @@ class Color4: public Vector4 { is fairly common, nearly always with A set to 1 */ constexpr /*implicit*/ Color4(const Vector3& rgb, T a = Implementation::fullChannel()) noexcept: Vector4(rgb[0], rgb[1], rgb[2], a) {} + /** @copydoc Vector::Vector(const T(&)[size_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Color4(const T(&data)[size_]) noexcept: Vector4{data} {} + #else + /* GCC 4.8 workaround, see the Vector base for details */ + constexpr explicit Color4(const T(&data)[4]) noexcept: Vector4{data} {} + #endif + /** * @copydoc Vector::Vector(const Vector&) * diff --git a/src/Magnum/Math/Matrix.h b/src/Magnum/Math/Matrix.h index cffdcb865..3c636825f 100644 --- a/src/Magnum/Math/Matrix.h +++ b/src/Magnum/Math/Matrix.h @@ -89,6 +89,14 @@ template class Matrix: public RectangularMatrix{value} {} + /** @copydoc RectangularMatrix::RectangularMatrix(const T(&)[cols_][rows_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Matrix(const T(&data)[cols_][rows_]) noexcept: RectangularMatrix{data} {} + #else + /* GCC 4.8 workaround, see the RectangularMatrix base for details */ + constexpr explicit Matrix(const T(&data)[size][size]) noexcept: RectangularMatrix{data} {} + #endif + /** * @brief Construct from a matrix of a different type * diff --git a/src/Magnum/Math/Matrix3.h b/src/Magnum/Math/Matrix3.h index 5e0f0ee47..2cf4ebcb3 100644 --- a/src/Magnum/Math/Matrix3.h +++ b/src/Magnum/Math/Matrix3.h @@ -301,6 +301,14 @@ template class Matrix3: public Matrix3x3 { /** @brief Construct with one value for all elements */ constexpr explicit Matrix3(T value) noexcept: Matrix3x3{value} {} + /** @copydoc Matrix::Matrix(const T(&)[cols_][rows_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Matrix3(const T(&data)[cols_][rows_]) noexcept: Matrix3x3{data} {} + #else + /* GCC 4.8 workaround, see the RectangularMatrix base for details */ + constexpr explicit Matrix3(const T(&data)[3][3]) noexcept: Matrix3x3{data} {} + #endif + /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ template constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other) noexcept: Matrix3x3(other) {} diff --git a/src/Magnum/Math/Matrix4.h b/src/Magnum/Math/Matrix4.h index 85b7873ee..1dc3d2eec 100644 --- a/src/Magnum/Math/Matrix4.h +++ b/src/Magnum/Math/Matrix4.h @@ -567,6 +567,14 @@ template class Matrix4: public Matrix4x4 { /** @brief Construct with one value for all elements */ constexpr explicit Matrix4(T value) noexcept: Matrix4x4{value} {} + /** @copydoc Matrix::Matrix(const T(&)[cols_][rows_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Matrix4(const T(&data)[cols_][rows_]) noexcept: Matrix4x4{data} {} + #else + /* GCC 4.8 workaround, see the RectangularMatrix base for details */ + constexpr explicit Matrix4(const T(&data)[4][4]) noexcept: Matrix4x4{data} {} + #endif + /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ template constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other) noexcept: Matrix4x4(other) {} diff --git a/src/Magnum/Math/RectangularMatrix.h b/src/Magnum/Math/RectangularMatrix.h index 77ea6d11a..f50932e06 100644 --- a/src/Magnum/Math/RectangularMatrix.h +++ b/src/Magnum/Math/RectangularMatrix.h @@ -110,8 +110,9 @@ template class RectangularMatrix { * @return Reference to the data as if it was matrix, thus doesn't * perform any copying. * - * @attention Use with caution, the function doesn't check whether the - * array is long enough. + * Use with caution, the function doesn't check whether the array is + * long enough. If possible, prefer to use the + * @ref RectangularMatrix(const T(&)[cols_][rows_]) constructor. */ static RectangularMatrix& from(T* data) { return *reinterpret_cast*>(data); @@ -176,6 +177,24 @@ template class RectangularMatrix { /** @brief Construct with one value for all components */ constexpr explicit RectangularMatrix(T value) noexcept: RectangularMatrix{typename Containers::Implementation::GenerateSequence::Type{}, value} {} + /** + * @brief Construct from a fixed-size array + * @m_since_latest + * + * Use @ref Vector::from(T*) "from(const T*)" to reinterpret an + * arbitrary pointer to a matrix. + */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit RectangularMatrix(const T(&data)[cols_][rows_]) noexcept: RectangularMatrix{typename Containers::Implementation::GenerateSequence::Type{}, data} { + static_assert(cols_ == cols && rows_ == rows, "wrong number of initializers"); + } + #else + /* GCC 4.8 isn't able to figure out the size on its own. Which means + there we use the type-provided size and lose the check for element + count, but at least it compiles. */ + constexpr explicit RectangularMatrix(const T(&data)[cols][rows]) noexcept: RectangularMatrix{typename Containers::Implementation::GenerateSequence::Type{}, data} {} + #endif + /** * @brief Construct from a matrix of a different type * @@ -588,6 +607,10 @@ template class RectangularMatrix { /* Implementation for RectangularMatrix::fromDiagonal() and RectangularMatrix(IdentityInitT, T) */ template constexpr explicit RectangularMatrix(Containers::Implementation::Sequence, const Vector& diagonal); + /* Implementation for RectangularMatrix::RectangularMatrix(const T(&data)[cols_][rows_]). + Can't use Vector{} here because MSVC 2015 chokes on it. */ + template constexpr explicit RectangularMatrix(Containers::Implementation::Sequence, const T(&data)[sizeof...(sequence)][rows_]) noexcept: _data{Vector(data[sequence])...} {} + /* Implementation for RectangularMatrix::RectangularMatrix(const RectangularMatrix&) */ template constexpr explicit RectangularMatrix(Containers::Implementation::Sequence, const RectangularMatrix& matrix) noexcept: _data{Vector(matrix[sequence])...} {} diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index 4ae0dbcb0..707a740fc 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -83,6 +83,8 @@ struct ColorTest: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructParts(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructBit(); void constructPacking(); @@ -212,6 +214,8 @@ ColorTest::ColorTest() { &ColorTest::constructNoInit, &ColorTest::constructOneValue, &ColorTest::constructParts, + &ColorTest::constructArray, + &ColorTest::constructArrayRvalue, &ColorTest::constructConversion, &ColorTest::constructBit, &ColorTest::constructPacking, @@ -411,6 +415,65 @@ void ColorTest::constructParts() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void ColorTest::constructArray() { + float data3[]{1.3f, 2.7f, -15.0f}; + float data4[]{1.3f, 2.7f, -15.0f, 7.0f}; + Color3 a3{data3}; + Color4 a4{data4}; + CORRADE_COMPARE(a3, (Color3{1.3f, 2.7f, -15.0f})); + CORRADE_COMPARE(a4, (Color4{1.3f, 2.7f, -15.0f, 7.0f})); + + constexpr float cdata3[]{1.3f, 2.7f, -15.0f}; + constexpr float cdata4[]{1.3f, 2.7f, -15.0f, 7.0f}; + constexpr Color3 ca3{cdata3}; + constexpr Color4 ca4{cdata4}; + CORRADE_COMPARE(ca3, (Color3{1.3f, 2.7f, -15.0f})); + CORRADE_COMPARE(ca4, (Color4{1.3f, 2.7f, -15.0f, 7.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See VectorTest::constructArray() for details */ + #if 0 + float data1[]{1.3f}; + float data5[]{1.3f, 2.7f, -15.0f, 7.0f, 22.6f}; + Color3 b3{data1}; + Color4 b4{data1}; + Color3 c3{data5}; + Color4 c4{data5}; + #endif +} + +void ColorTest::constructArrayRvalue() { + /* Silly but why not. Could theoretically help with some fancier types + that'd otherwise require explicit typing with the variadic + constructor. */ + Color3 a3{{1.3f, 2.7f, -15.0f}}; + Color4 a4{{1.3f, 2.7f, -15.0f, 7.0f}}; + CORRADE_COMPARE(a3, (Color3{1.3f, 2.7f, -15.0f})); + CORRADE_COMPARE(a4, (Color4{1.3f, 2.7f, -15.0f, 7.0f})); + + constexpr Color3 ca3{{1.3f, 2.7f, -15.0f}}; + constexpr Color4 ca4{{1.3f, 2.7f, -15.0f, 7.0f}}; + CORRADE_COMPARE(ca3, (Color3{1.3f, 2.7f, -15.0f})); + CORRADE_COMPARE(ca4, (Color4{1.3f, 2.7f, -15.0f, 7.0f})); + + /* See VectorTest::constructArrayRvalue() for details */ + #if 0 + Color3 c3{{1.3f, 2.7f, -15.0f, 7.0f}}; + Color4 c4{{1.3f, 2.7f, -15.0f, 7.0f, 22.6f}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Color from a smaller array isn't an error on GCC 4.8."); + Color3 b3{{1.3f, 2.7f}}; + Color4 b4{{1.3f, 2.7f}}; + #endif +} + void ColorTest::constructConversion() { constexpr Color3 a(10.1f, 12.5f, 0.75f); constexpr Color3ub b(a); diff --git a/src/Magnum/Math/Test/Matrix3Test.cpp b/src/Magnum/Math/Test/Matrix3Test.cpp index 5e686a2c2..201163ffd 100644 --- a/src/Magnum/Math/Test/Matrix3Test.cpp +++ b/src/Magnum/Math/Test/Matrix3Test.cpp @@ -65,6 +65,8 @@ struct Matrix3Test: TestSuite::Tester { void constructZero(); void constructNoInit(); void constructOneValue(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructFromDifferentSize(); void constructCopy(); @@ -121,6 +123,8 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::constructZero, &Matrix3Test::constructNoInit, &Matrix3Test::constructOneValue, + &Matrix3Test::constructArray, + &Matrix3Test::constructArrayRvalue, &Matrix3Test::constructConversion, &Matrix3Test::constructFromDifferentSize, &Matrix3Test::constructCopy, @@ -244,6 +248,96 @@ void Matrix3Test::constructOneValue() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Matrix3Test::constructArray() { + float data[3][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f} + }; + Matrix3 a{data}; + CORRADE_COMPARE(a, (Matrix3{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}})); + + constexpr float cdata[3][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f} + }; + constexpr Matrix3 ca{cdata}; + CORRADE_COMPARE(ca, (Matrix3{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See RectangularMatrixTest::constructArray() for details */ + #if 0 + float data32[3][2]{ + {3.0f, 5.0f}, + {4.5f, 4.0f}, + {1.0f, 2.0f} + }; + float data34[3][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f} + }; + float data13[1][3]{ + {3.0f, 5.0f, 8.0f}, + }; + float data43[4][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {4.5f, 4.0f, 7.0f}, + {4.5f, 4.0f, 7.0f} + }; + Matrix3 b{data32}; + Matrix3 c{data34}; + Matrix3 d{data13}; + Matrix3 e{data43}; + #endif +} + +void Matrix3Test::constructArrayRvalue() { + /* In this case the constructor already has concrete types, so the array + constructor doesn't really add anything to it */ + Matrix3 a{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}}}; + CORRADE_COMPARE(a, (Matrix3{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}})); + + constexpr Matrix3 ca{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}}}; + CORRADE_COMPARE(ca, (Matrix3{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}})); + + /* See RectangularMatrixTest::constructArrayRvalue() for details */ + #if 0 + Matrix3 c{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}}}; + Matrix3 e{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {4.5f, 4.0f, 7.0f}, + {4.5f, 4.0f, 7.0f}}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Matrix from a smaller array isn't an error on GCC 4.8."); + Matrix3 b{{{3.0f, 5.0f}, + {4.5f, 4.0f}, + {1.0f, 2.0f}}}; + Matrix3 d{{{3.0f, 5.0f, 8.0f}}}; + #endif +} + void Matrix3Test::constructConversion() { constexpr Matrix3 a({3.0f, 5.0f, 8.0f}, {4.5f, 4.0f, 7.0f}, diff --git a/src/Magnum/Math/Test/Matrix4Test.cpp b/src/Magnum/Math/Test/Matrix4Test.cpp index 64b7af106..7987cf5c4 100644 --- a/src/Magnum/Math/Test/Matrix4Test.cpp +++ b/src/Magnum/Math/Test/Matrix4Test.cpp @@ -68,6 +68,8 @@ struct Matrix4Test: TestSuite::Tester { void constructZero(); void constructNoInit(); void constructOneValue(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructFromDifferentSize(); void constructCopy(); @@ -144,6 +146,8 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::constructZero, &Matrix4Test::constructNoInit, &Matrix4Test::constructOneValue, + &Matrix4Test::constructArray, + &Matrix4Test::constructArrayRvalue, &Matrix4Test::constructConversion, &Matrix4Test::constructFromDifferentSize, &Matrix4Test::constructCopy, @@ -292,6 +296,110 @@ void Matrix4Test::constructOneValue() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Matrix4Test::constructArray() { + float data[4][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f} + }; + Matrix4 a{data}; + CORRADE_COMPARE(a, (Matrix4{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}})); + + constexpr float cdata[4][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f} + }; + constexpr Matrix4 ca{cdata}; + CORRADE_COMPARE(ca, (Matrix4{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See RectangularMatrixTest::constructArray() for details */ + #if 0 + float data43[4][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}, + {7.9f, -1.0f, 8.0f} + }; + float data45[4][5]{ + {3.0f, 5.0f, 8.0f, -3.0f, 0.3f}, + {4.5f, 4.0f, 7.0f, 2.0f, 0.3f}, + {1.0f, 2.0f, 3.0f, -1.0f, 0.3f}, + {7.9f, -1.0f, 8.0f, -1.5f, 0.3f} + }; + float data14[1][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + }; + float data54[5][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f} + }; + Matrix4 b{data43}; + Matrix4 c{data45}; + Matrix4 d{data14}; + Matrix4 e{data54}; + #endif +} + +void Matrix4Test::constructArrayRvalue() { + /* In this case the constructor already has concrete types, so the array + constructor doesn't really add anything to it */ + Matrix4 a{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}}}; + CORRADE_COMPARE(a, (Matrix4{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}})); + + constexpr Matrix4 ca{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}}}; + CORRADE_COMPARE(ca, (Matrix4{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}})); + + /* See RectangularMatrixTest::constructArrayRvalue() for details */ + #if 0 + Matrix4 c{{{3.0f, 5.0f, 8.0f, -3.0f, 0.3f}, + {4.5f, 4.0f, 7.0f, 2.0f, 0.3f}, + {1.0f, 2.0f, 3.0f, -1.0f, 0.3f}, + {7.9f, -1.0f, 8.0f, -1.5f, 0.3f}}}; + Matrix4 e{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f}}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Matrix from a smaller array isn't an error on GCC 4.8."); + Matrix4 b{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}, + {7.9f, -1.0f, 8.0f}}}; + Matrix4 d{{{3.0f, 5.0f, 8.0f, -3.0f}}}; + #endif +} + void Matrix4Test::constructConversion() { constexpr Matrix4 a({3.0f, 5.0f, 8.0f, -3.0f}, {4.5f, 4.0f, 7.0f, 2.0f}, diff --git a/src/Magnum/Math/Test/MatrixTest.cpp b/src/Magnum/Math/Test/MatrixTest.cpp index 986f215c4..2cbb7e726 100644 --- a/src/Magnum/Math/Test/MatrixTest.cpp +++ b/src/Magnum/Math/Test/MatrixTest.cpp @@ -66,6 +66,8 @@ struct MatrixTest: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructOneComponent(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructFromDifferentSize(); void constructCopy(); @@ -110,6 +112,8 @@ MatrixTest::MatrixTest() { &MatrixTest::constructNoInit, &MatrixTest::constructOneValue, &MatrixTest::constructOneComponent, + &MatrixTest::constructArray, + &MatrixTest::constructArrayRvalue, &MatrixTest::constructConversion, &MatrixTest::constructFromDifferentSize, &MatrixTest::constructCopy, @@ -237,6 +241,110 @@ void MatrixTest::constructOneComponent() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void MatrixTest::constructArray() { + float data[4][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f} + }; + Matrix4x4 a{data}; + CORRADE_COMPARE(a, (Matrix4x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}, + Vector4{1.0f, 2.0f, 3.0f, -1.0f}, + Vector4{7.9f, -1.0f, 8.0f, -1.5f}})); + + constexpr float cdata[4][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f} + }; + constexpr Matrix4x4 ca{cdata}; + CORRADE_COMPARE(ca, (Matrix4x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}, + Vector4{1.0f, 2.0f, 3.0f, -1.0f}, + Vector4{7.9f, -1.0f, 8.0f, -1.5f}})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See RectangularMatrixTest::constructArray() for details */ + #if 0 + float data43[4][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}, + {7.9f, -1.0f, 8.0f} + }; + float data45[4][5]{ + {3.0f, 5.0f, 8.0f, -3.0f, 0.3f}, + {4.5f, 4.0f, 7.0f, 2.0f, 0.3f}, + {1.0f, 2.0f, 3.0f, -1.0f, 0.3f}, + {7.9f, -1.0f, 8.0f, -1.5f, 0.3f} + }; + float data14[1][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + }; + float data54[5][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f} + }; + Matrix4x4 b{data43}; + Matrix4x4 c{data45}; + Matrix4x4 d{data14}; + Matrix4x4 e{data54}; + #endif +} + +void MatrixTest::constructArrayRvalue() { + /* This, the extra {} to supply an array, avoids the need to have to + explicitly type out Vector for every column */ + Matrix4x4 a{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}}}; + CORRADE_COMPARE(a, (Matrix4x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}, + Vector4{1.0f, 2.0f, 3.0f, -1.0f}, + Vector4{7.9f, -1.0f, 8.0f, -1.5f}})); + + constexpr Matrix4x4 ca{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}}}; + CORRADE_COMPARE(ca, (Matrix4x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}, + Vector4{1.0f, 2.0f, 3.0f, -1.0f}, + Vector4{7.9f, -1.0f, 8.0f, -1.5f}})); + + /* See RectangularMatrixTest::constructArrayRvalue() for details */ + #if 0 + Matrix4x4 c{{{3.0f, 5.0f, 8.0f, -3.0f, 0.3f}, + {4.5f, 4.0f, 7.0f, 2.0f, 0.3f}, + {1.0f, 2.0f, 3.0f, -1.0f, 0.3f}, + {7.9f, -1.0f, 8.0f, -1.5f, 0.3f}}}; + Matrix4x4 e{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f}}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Matrix from a smaller array isn't an error on GCC 4.8."); + Matrix4x4 b{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}, + {7.9f, -1.0f, 8.0f}}}; + Matrix4x4 d{{{3.0f, 5.0f, 8.0f, -3.0f}}}; + #endif +} + void MatrixTest::constructConversion() { constexpr Matrix4x4 a(Vector4(3.0f, 5.0f, 8.0f, -3.0f), Vector4(4.5f, 4.0f, 7.0f, 2.0f), diff --git a/src/Magnum/Math/Test/RectangularMatrixTest.cpp b/src/Magnum/Math/Test/RectangularMatrixTest.cpp index 8b40c6786..b40b01428 100644 --- a/src/Magnum/Math/Test/RectangularMatrixTest.cpp +++ b/src/Magnum/Math/Test/RectangularMatrixTest.cpp @@ -64,6 +64,8 @@ struct RectangularMatrixTest: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructOneComponent(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructFromDifferentSize(); void constructFromData(); @@ -131,6 +133,8 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::constructNoInit, &RectangularMatrixTest::constructOneValue, &RectangularMatrixTest::constructOneComponent, + &RectangularMatrixTest::constructArray, + &RectangularMatrixTest::constructArrayRvalue, &RectangularMatrixTest::constructConversion, &RectangularMatrixTest::constructFromDifferentSize, &RectangularMatrixTest::constructFromData, @@ -265,6 +269,100 @@ void RectangularMatrixTest::constructOneComponent() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void RectangularMatrixTest::constructArray() { + float data[2][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + }; + Matrix2x4 a{data}; + CORRADE_COMPARE(a, (Matrix2x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}})); + + constexpr float cdata[2][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + }; + constexpr Matrix2x4 ca{cdata}; + CORRADE_COMPARE(ca, (Matrix2x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* It should always be constructible only with exactly the matching number + of elements. As that's checked with a static_assert(), it's impossible + to verify with std::is_constructible unfortunately and the only way to + test that is manually, thus uncomment the code below to test the error + behavior. + + Additionally, to avoid noise in the compiler output, the second and + fourth should only produce "excess elements in array initializer" and a + static assert, the first and third just a static assert, no other + compiler error. */ + #if 0 + float data23[2][3]{ + {3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f} + }; + float data25[2][5]{ + {3.0f, 5.0f, 8.0f, -3.0f, 17.0f}, + {4.5f, 4.0f, 7.0f, 2.0f, 23.2f} + }; + float data14[1][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + }; + float data34[3][4]{ + {3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f} + }; + Matrix2x4 b{data23}; + Matrix2x4 c{data25}; + Matrix2x4 d{data14}; + Matrix2x4 e{data34}; + #endif +} + +void RectangularMatrixTest::constructArrayRvalue() { + /* This, the extra {} to supply an array, avoids the need to have to + explicitly type out Vector for every column */ + Matrix2x4 a{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}}}; + CORRADE_COMPARE(a, (Matrix2x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}})); + + constexpr Matrix2x4 ca{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}}}; + CORRADE_COMPARE(ca, (Matrix2x4{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}})); + + /* It should always be constructible only with exactly the matching number + of elements. As that's checked with a static_assert(), it's impossible + to verify with std::is_constructible unfortunately and the only way to + test that is manually, thus uncomment the code below to test the error + behavior. + + Additionally, to avoid noise in the compiler output, the first and + second should only produce "excess elements in array initializer" and a + static assert, the third and fourth a static assert, no other compiler + error. */ + #if 0 + Matrix2x4 c{{{3.0f, 5.0f, 8.0f, -3.0f, 17.0f}, + {4.5f, 4.0f, 7.0f, 2.0f, 23.2f}}}; + Matrix2x4 e{{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {3.0f, 7.0f, 0.0f, 1.0f}}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a RectangularMatrix from a smaller array isn't an error on GCC 4.8."); + Matrix2x4 b{{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}}}; + Matrix2x4 d{{{3.0f, 5.0f, 8.0f, -3.0f}}}; + #endif +} + void RectangularMatrixTest::constructConversion() { constexpr Matrix2x2 a(Vector2( 1.3f, 2.7f), Vector2(-15.0f, 7.0f)); diff --git a/src/Magnum/Math/Test/Vector2Test.cpp b/src/Magnum/Math/Test/Vector2Test.cpp index bc753bb4c..24272a1c4 100644 --- a/src/Magnum/Math/Test/Vector2Test.cpp +++ b/src/Magnum/Math/Test/Vector2Test.cpp @@ -60,6 +60,8 @@ struct Vector2Test: TestSuite::Tester { void constructDefault(); void constructNoInit(); void constructOneValue(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructBit(); void constructCopy(); @@ -87,6 +89,8 @@ Vector2Test::Vector2Test() { &Vector2Test::constructDefault, &Vector2Test::constructNoInit, &Vector2Test::constructOneValue, + &Vector2Test::constructArray, + &Vector2Test::constructArrayRvalue, &Vector2Test::constructConversion, &Vector2Test::constructBit, &Vector2Test::constructCopy, @@ -156,6 +160,48 @@ void Vector2Test::constructOneValue() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector2Test::constructArray() { + float data[]{1.3f, 2.7f}; + Vector2 a{data}; + CORRADE_COMPARE(a, (Vector2{1.3f, 2.7f})); + + constexpr float cdata[]{1.3f, 2.7f}; + constexpr Vector2 ca{cdata}; + CORRADE_COMPARE(ca, (Vector2{1.3f, 2.7f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See VectorTest::constructArray() for details */ + #if 0 + float data1[]{1.3f}; + float data4[]{1.3f, 2.7f, -15.0f, 7.0f}; + Vector2 b{data1}; + Vector2 c{data4}; + #endif +} + +void Vector2Test::constructArrayRvalue() { + /* Silly but why not. Could theoretically help with some fancier types + that'd otherwise require explicit typing with the variadic + constructor. */ + Vector2 a{{1.3f, 2.7f}}; + CORRADE_COMPARE(a, (Vector2{1.3f, 2.7f})); + + constexpr Vector2 ca{{1.3f, 2.7f}}; + CORRADE_COMPARE(ca, (Vector2{1.3f, 2.7f})); + + /* See VectorTest::constructArrayRvalue() for details. In case of a + two-component vector, doing Vector2{{1.3f}} isn't an error, as it picks + the one-value overload, and possibly only warns about "braces around + scalar initializer". */ + #if 0 + Vector2 c{{1.3f, 2.7f, -15.0f, 7.0f}}; + #endif +} + void Vector2Test::constructConversion() { constexpr Vector2 a(1.5f, 2.5f); constexpr Vector2i b(a); diff --git a/src/Magnum/Math/Test/Vector3Test.cpp b/src/Magnum/Math/Test/Vector3Test.cpp index daa20ae01..c8b76fac1 100644 --- a/src/Magnum/Math/Test/Vector3Test.cpp +++ b/src/Magnum/Math/Test/Vector3Test.cpp @@ -61,6 +61,8 @@ struct Vector3Test: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructParts(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructBit(); void constructCopy(); @@ -89,6 +91,8 @@ Vector3Test::Vector3Test() { &Vector3Test::constructNoInit, &Vector3Test::constructOneValue, &Vector3Test::constructParts, + &Vector3Test::constructArray, + &Vector3Test::constructArrayRvalue, &Vector3Test::constructConversion, &Vector3Test::constructBit, &Vector3Test::constructCopy, @@ -165,6 +169,49 @@ void Vector3Test::constructParts() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector3Test::constructArray() { + float data[]{1.3f, 2.7f, -15.0f}; + Vector3 a{data}; + CORRADE_COMPARE(a, (Vector3{1.3f, 2.7f, -15.0f})); + + constexpr float cdata[]{1.3f, 2.7f, -15.0f}; + constexpr Vector3 ca{cdata}; + CORRADE_COMPARE(ca, (Vector3{1.3f, 2.7f, -15.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See VectorTest::constructArray() for details */ + #if 0 + float data1[]{1.3f}; + float data4[]{1.3f, 2.7f, -15.0f, 7.0f}; + Vector3 b{data1}; + Vector3 c{data4}; + #endif +} + +void Vector3Test::constructArrayRvalue() { + /* Silly but why not. Could theoretically help with some fancier types + that'd otherwise require explicit typing with the variadic + constructor. */ + Vector3 a{{1.3f, 2.7f, -15.0f}}; + CORRADE_COMPARE(a, (Vector3{1.3f, 2.7f, -15.0f})); + + constexpr Vector3 ca{{1.3f, 2.7f, -15.0f}}; + CORRADE_COMPARE(ca, (Vector3{1.3f, 2.7f, -15.0f})); + + /* See VectorTest::constructArrayRvalue() for details */ + #if 0 + Vector3 c{{1.3f, 2.7f, -15.0f, 7.0f}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Vector from a smaller array isn't an error on GCC 4.8."); + Vector3 b{{1.3f, 2.7f}}; + #endif +} + void Vector3Test::constructConversion() { constexpr Vector3 a(1.0f, 2.5f, -3.0f); constexpr Vector3i b(a); diff --git a/src/Magnum/Math/Test/Vector4Test.cpp b/src/Magnum/Math/Test/Vector4Test.cpp index f94899e02..60a119fa4 100644 --- a/src/Magnum/Math/Test/Vector4Test.cpp +++ b/src/Magnum/Math/Test/Vector4Test.cpp @@ -62,6 +62,8 @@ struct Vector4Test: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructParts(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructBit(); void constructCopy(); @@ -93,6 +95,8 @@ Vector4Test::Vector4Test() { &Vector4Test::constructNoInit, &Vector4Test::constructOneValue, &Vector4Test::constructParts, + &Vector4Test::constructArray, + &Vector4Test::constructArrayRvalue, &Vector4Test::constructConversion, &Vector4Test::constructBit, &Vector4Test::constructCopy, @@ -186,6 +190,49 @@ void Vector4Test::constructParts() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector4Test::constructArray() { + float data[]{1.3f, 2.7f, -15.0f, 7.0f}; + Vector4 a{data}; + CORRADE_COMPARE(a, (Vector4{1.3f, 2.7f, -15.0f, 7.0f})); + + constexpr float cdata[]{1.3f, 2.7f, -15.0f, 7.0f}; + constexpr Vector4 ca{cdata}; + CORRADE_COMPARE(ca, (Vector4{1.3f, 2.7f, -15.0f, 7.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* See VectorTest::constructArray() for details */ + #if 0 + float data1[]{1.3f}; + float data5[]{1.3f, 2.7f, -15.0f, 7.0f, 22.6f}; + Vector4 b{data1}; + Vector4 c{data5}; + #endif +} + +void Vector4Test::constructArrayRvalue() { + /* Silly but why not. Could theoretically help with some fancier types + that'd otherwise require explicit typing with the variadic + constructor. */ + Vector4 a{{1.3f, 2.7f, -15.0f, 7.0f}}; + CORRADE_COMPARE(a, (Vector4{1.3f, 2.7f, -15.0f, 7.0f})); + + constexpr Vector4 ca{{1.3f, 2.7f, -15.0f, 7.0f}}; + CORRADE_COMPARE(ca, (Vector4{1.3f, 2.7f, -15.0f, 7.0f})); + + /* See VectorTest::constructArrayRvalue() for details */ + #if 0 + Vector4 c{{1.3f, 2.7f, -15.0f, 7.0f, 22.6f}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Vector from a smaller array isn't an error on GCC 4.8."); + Vector4 b{{1.3f, 2.7f}}; + #endif +} + void Vector4Test::constructConversion() { constexpr Vector4 a(1.0f, -2.5f, 3.0f, 4.1f); constexpr Vector4i b(a); diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index da6da6297..8cb1570c3 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -65,6 +65,8 @@ struct VectorTest: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructOneComponent(); + void constructArray(); + void constructArrayRvalue(); void constructConversion(); void constructBit(); void constructCopy(); @@ -145,6 +147,8 @@ VectorTest::VectorTest() { &VectorTest::constructNoInit, &VectorTest::constructOneValue, &VectorTest::constructOneComponent, + &VectorTest::constructArray, + &VectorTest::constructArrayRvalue, &VectorTest::constructConversion, &VectorTest::constructBit, &VectorTest::constructCopy, @@ -286,6 +290,65 @@ void VectorTest::constructOneComponent() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void VectorTest::constructArray() { + float data[]{1.3f, 2.7f, -15.0f}; + Vector3 a{data}; + CORRADE_COMPARE(a, (Vector3{1.3f, 2.7f, -15.0f})); + + constexpr float cdata[]{1.3f, 2.7f, -15.0f}; + constexpr Vector3 ca{cdata}; + CORRADE_COMPARE(ca, (Vector3{1.3f, 2.7f, -15.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* It should always be constructible only with exactly the matching number + of elements. As that's checked with a static_assert(), it's impossible + to verify with std::is_constructible unfortunately and the only way to + test that is manually, thus uncomment the code below to test the error + behavior. + + Additionally, to avoid noise in the compiler output, the first should + only produce "excess elements in array initializer" and a static assert, + the second just a static assert, no other compiler error. */ + #if 0 + float data1[]{1.3f}; + float data4[]{1.3f, 2.7f, -15.0f, 7.0f}; + Vector3 b{data1}; + Vector3 c{data4}; + #endif +} + +void VectorTest::constructArrayRvalue() { + /* Silly but why not. Could theoretically help with some fancier types + that'd otherwise require explicit typing with the variadic + constructor. */ + Vector3 a{{1.3f, 2.7f, -15.0f}}; + CORRADE_COMPARE(a, (Vector3{1.3f, 2.7f, -15.0f})); + + constexpr Vector3 ca{{1.3f, 2.7f, -15.0f}}; + CORRADE_COMPARE(ca, (Vector3{1.3f, 2.7f, -15.0f})); + + /* It should always be constructible only with exactly the matching number + of elements. As that's checked with a static_assert(), it's impossible + to verify with std::is_constructible unfortunately and the only way to + test that is manually, thus uncomment the code below to test the error + behavior. + + Additionally, to avoid noise in the compiler output, the first should + only produce "excess elements in array initializer" and a static assert, + the second just a static assert, no other compiler error. */ + #if 0 + Vector3 c{{1.3f, 2.7f, -15.0f, 7.0f}}; + #endif + #if 0 || (defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5) + CORRADE_WARN("Creating a Vector from a smaller array isn't an error on GCC 4.8."); + Vector3 b{{1.3f, 2.7f}}; + #endif +} + void VectorTest::constructConversion() { constexpr Vector4 a(1.3f, 2.7f, -15.0f, 7.0f); constexpr Vector4i b(a); diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 97c625943..9aa0bc200 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -170,8 +170,9 @@ template class Vector { * @return Reference to the data as if it was Vector, thus doesn't * perform any copying. * - * @attention Use with caution, the function doesn't check whether the - * array is long enough. + * Use with caution, the function doesn't check whether the array is + * long enough. If possible, prefer to use the + * @ref Vector(const T(&)[size_]) constructor. */ static Vector& from(T* data) { return *reinterpret_cast*>(data); @@ -218,6 +219,24 @@ template class Vector { template::type> constexpr /*implicit*/ Vector(T first, U... next) noexcept: _data{first, next...} {} #endif + /** + * @brief Construct a vector from a fixed-size array + * @m_since_latest + * + * Use @ref Vector::from(T*) "from(const T*)" to reinterpret an + * arbitrary pointer to a vector. + */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Vector(const T(&data)[size_]) noexcept: Vector{typename Containers::Implementation::GenerateSequence::Type{}, data} { + static_assert(size_ == size, "wrong number of initializers"); + } + #else + /* GCC 4.8 isn't able to figure out the size on its own. Which means + there we use the type-provided size and lose the check for element + count, but at least it compiles. */ + constexpr explicit Vector(const T(&data)[size]) noexcept: Vector{typename Containers::Implementation::GenerateSequence::Type{}, data} {} + #endif + /** @brief Construct a vector with one value for all components */ #ifdef DOXYGEN_GENERATING_OUTPUT constexpr explicit Vector(T value) noexcept; @@ -1263,6 +1282,9 @@ template class Vector { template friend U dot(const Vector&, const Vector&); + /* Implementation for Vector::Vector(const T(&data)[size_]) */ + template constexpr explicit Vector(Containers::Implementation::Sequence, const T(&data)[sizeof...(sequence)]) noexcept: _data{data[sequence]...} {} + /* Implementation for Vector::Vector(const Vector&) */ template constexpr explicit Vector(Containers::Implementation::Sequence, const Vector& vector) noexcept: _data{T(vector._data[sequence])...} {} diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index 7b5f1903d..b9874e0c2 100644 --- a/src/Magnum/Math/Vector2.h +++ b/src/Magnum/Math/Vector2.h @@ -138,6 +138,14 @@ template class Vector2: public Vector<2, T> { */ constexpr /*implicit*/ Vector2(T x, T y) noexcept: Vector<2, T>(x, y) {} + /** @copydoc Vector::Vector(const T(&)[size_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Vector2(const T(&data)[size_]) noexcept: Vector<2, T>{data} {} + #else + /* GCC 4.8 workaround, see the Vector base for details */ + constexpr explicit Vector2(const T(&data)[2]) noexcept: Vector<2, T>{data} {} + #endif + /** @copydoc Vector::Vector(const Vector&) */ template constexpr explicit Vector2(const Vector<2, U>& other) noexcept: Vector<2, T>(other) {} diff --git a/src/Magnum/Math/Vector3.h b/src/Magnum/Math/Vector3.h index 45db79529..cbf443b5a 100644 --- a/src/Magnum/Math/Vector3.h +++ b/src/Magnum/Math/Vector3.h @@ -166,6 +166,14 @@ template class Vector3: public Vector<3, T> { */ constexpr /*implicit*/ Vector3(const Vector2& xy, T z) noexcept: Vector<3, T>(xy[0], xy[1], z) {} + /** @copydoc Vector::Vector(const T(&)[size_]) */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Vector3(const T(&data)[size_]) noexcept: Vector<3, T>{data} {} + #else + /* GCC 4.8 workaround, see the Vector base for details */ + constexpr explicit Vector3(const T(&data)[3]) noexcept: Vector<3, T>{data} {} + #endif + /** @copydoc Vector::Vector(const Vector&) */ template constexpr explicit Vector3(const Vector<3, U>& other) noexcept: Vector<3, T>(other) {} diff --git a/src/Magnum/Math/Vector4.h b/src/Magnum/Math/Vector4.h index 08d639cd4..e8f1cda07 100644 --- a/src/Magnum/Math/Vector4.h +++ b/src/Magnum/Math/Vector4.h @@ -108,6 +108,17 @@ template class Vector4: public Vector<4, T> { */ constexpr /*implicit*/ Vector4(const Vector3& xyz, T w) noexcept: Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} + /** @copydoc Magnum::Math::Vector::Vector(const T(&)[size_]) */ + /* For some freaking reason doxygen 1.8.17 needs a fully qualified name + here but GUESS WHAT! Not in the other Vector2/3 classes! Dumpster + fire! FFS. */ + #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 + template constexpr explicit Vector4(const T(&data)[size_]) noexcept: Vector<4, T>{data} {} + #else + /* GCC 4.8 workaround, see the Vector base for details */ + constexpr explicit Vector4(const T(&data)[4]) noexcept: Vector<4, T>{data} {} + #endif + /** @copydoc Magnum::Math::Vector::Vector(const Vector&) */ /* For some freaking reason doxygen 1.8.17 needs a fully qualified name here but GUESS WHAT! Not in the other Vector2/3 classes! Dumpster