Browse Source

Math: ability to construct vectors and matrices from sized arrays.

Same as done for Containers::StaticArray some time ago. Since it's not a
potentially dangerous operation, it's not made as an overload of the
from() function, but instead a regular constructor. It's however kept
explicit for now, even though it eventually might not need to be -- I'm
not sure about potential consequences yet.
pull/168/merge
Vladimír Vondruš 2 years ago
parent
commit
22b846e2e8
  1. 3
      doc/changelog.dox
  2. 16
      src/Magnum/Math/Color.h
  3. 8
      src/Magnum/Math/Matrix.h
  4. 8
      src/Magnum/Math/Matrix3.h
  5. 8
      src/Magnum/Math/Matrix4.h
  6. 27
      src/Magnum/Math/RectangularMatrix.h
  7. 63
      src/Magnum/Math/Test/ColorTest.cpp
  8. 94
      src/Magnum/Math/Test/Matrix3Test.cpp
  9. 108
      src/Magnum/Math/Test/Matrix4Test.cpp
  10. 108
      src/Magnum/Math/Test/MatrixTest.cpp
  11. 98
      src/Magnum/Math/Test/RectangularMatrixTest.cpp
  12. 46
      src/Magnum/Math/Test/Vector2Test.cpp
  13. 47
      src/Magnum/Math/Test/Vector3Test.cpp
  14. 47
      src/Magnum/Math/Test/Vector4Test.cpp
  15. 63
      src/Magnum/Math/Test/VectorTest.cpp
  16. 26
      src/Magnum/Math/Vector.h
  17. 8
      src/Magnum/Math/Vector2.h
  18. 8
      src/Magnum/Math/Vector3.h
  19. 11
      src/Magnum/Math/Vector4.h

3
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

16
src/Magnum/Math/Color.h

@ -561,6 +561,14 @@ template<class T> class Color3: public Vector3<T> {
*/
constexpr /*implicit*/ Color3(const Vector<2, T>& rg, T b) noexcept: Vector3<T>{rg, b} {}
/** @copydoc Vector::Vector(const T(&)[size_]) */
#if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5
template<std::size_t size_> constexpr explicit Color3(const T(&data)[size_]) noexcept: Vector3<T>{data} {}
#else
/* GCC 4.8 workaround, see the Vector base for details */
constexpr explicit Color3(const T(&data)[3]) noexcept: Vector3<T>{data} {}
#endif
/**
* @copydoc Vector::Vector(const Vector<size, U>&)
*
@ -1049,6 +1057,14 @@ class Color4: public Vector4<T> {
is fairly common, nearly always with A set to 1 */
constexpr /*implicit*/ Color4(const Vector3<T>& rgb, T a = Implementation::fullChannel<T>()) noexcept: Vector4<T>(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<std::size_t size_> constexpr explicit Color4(const T(&data)[size_]) noexcept: Vector4<T>{data} {}
#else
/* GCC 4.8 workaround, see the Vector base for details */
constexpr explicit Color4(const T(&data)[4]) noexcept: Vector4<T>{data} {}
#endif
/**
* @copydoc Vector::Vector(const Vector<size, U>&)
*

8
src/Magnum/Math/Matrix.h

@ -89,6 +89,14 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
/** @brief Construct with one value for all elements */
constexpr explicit Matrix(T value) noexcept: RectangularMatrix<size, size, T>{value} {}
/** @copydoc RectangularMatrix::RectangularMatrix(const T(&)[cols_][rows_]) */
#if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5
template<std::size_t cols_, std::size_t rows_> constexpr explicit Matrix(const T(&data)[cols_][rows_]) noexcept: RectangularMatrix<size, size, T>{data} {}
#else
/* GCC 4.8 workaround, see the RectangularMatrix base for details */
constexpr explicit Matrix(const T(&data)[size][size]) noexcept: RectangularMatrix<size, size, T>{data} {}
#endif
/**
* @brief Construct from a matrix of a different type
*

8
src/Magnum/Math/Matrix3.h

@ -301,6 +301,14 @@ template<class T> class Matrix3: public Matrix3x3<T> {
/** @brief Construct with one value for all elements */
constexpr explicit Matrix3(T value) noexcept: Matrix3x3<T>{value} {}
/** @copydoc Matrix::Matrix(const T(&)[cols_][rows_]) */
#if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5
template<std::size_t cols_, std::size_t rows_> constexpr explicit Matrix3(const T(&data)[cols_][rows_]) noexcept: Matrix3x3<T>{data} {}
#else
/* GCC 4.8 workaround, see the RectangularMatrix base for details */
constexpr explicit Matrix3(const T(&data)[3][3]) noexcept: Matrix3x3<T>{data} {}
#endif
/** @copydoc Matrix::Matrix(const RectangularMatrix<size, size, U>&) */
template<class U> constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other) noexcept: Matrix3x3<T>(other) {}

8
src/Magnum/Math/Matrix4.h

@ -567,6 +567,14 @@ template<class T> class Matrix4: public Matrix4x4<T> {
/** @brief Construct with one value for all elements */
constexpr explicit Matrix4(T value) noexcept: Matrix4x4<T>{value} {}
/** @copydoc Matrix::Matrix(const T(&)[cols_][rows_]) */
#if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5
template<std::size_t cols_, std::size_t rows_> constexpr explicit Matrix4(const T(&data)[cols_][rows_]) noexcept: Matrix4x4<T>{data} {}
#else
/* GCC 4.8 workaround, see the RectangularMatrix base for details */
constexpr explicit Matrix4(const T(&data)[4][4]) noexcept: Matrix4x4<T>{data} {}
#endif
/** @copydoc Matrix::Matrix(const RectangularMatrix<size, size, U>&) */
template<class U> constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other) noexcept: Matrix4x4<T>(other) {}

27
src/Magnum/Math/RectangularMatrix.h

@ -110,8 +110,9 @@ template<std::size_t cols, std::size_t rows, class T> 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<cols, rows, T>& from(T* data) {
return *reinterpret_cast<RectangularMatrix<cols, rows, T>*>(data);
@ -176,6 +177,24 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/** @brief Construct with one value for all components */
constexpr explicit RectangularMatrix(T value) noexcept: RectangularMatrix{typename Containers::Implementation::GenerateSequence<cols>::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<std::size_t cols_, std::size_t rows_> constexpr explicit RectangularMatrix(const T(&data)[cols_][rows_]) noexcept: RectangularMatrix{typename Containers::Implementation::GenerateSequence<cols_>::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<cols>::Type{}, data} {}
#endif
/**
* @brief Construct from a matrix of a different type
*
@ -588,6 +607,10 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/* Implementation for RectangularMatrix<cols, rows, T>::fromDiagonal() and RectangularMatrix<cols, rows, T>(IdentityInitT, T) */
template<std::size_t ...sequence> constexpr explicit RectangularMatrix(Containers::Implementation::Sequence<sequence...>, const Vector<DiagonalSize, T>& diagonal);
/* Implementation for RectangularMatrix<cols, rows, T>::RectangularMatrix(const T(&data)[cols_][rows_]).
Can't use Vector<rows, T>{} here because MSVC 2015 chokes on it. */
template<std::size_t rows_, std::size_t ...sequence> constexpr explicit RectangularMatrix(Containers::Implementation::Sequence<sequence...>, const T(&data)[sizeof...(sequence)][rows_]) noexcept: _data{Vector<rows, T>(data[sequence])...} {}
/* Implementation for RectangularMatrix<cols, rows, T>::RectangularMatrix(const RectangularMatrix<cols, rows, U>&) */
template<class U, std::size_t ...sequence> constexpr explicit RectangularMatrix(Containers::Implementation::Sequence<sequence...>, const RectangularMatrix<cols, rows, U>& matrix) noexcept: _data{Vector<rows, T>(matrix[sequence])...} {}

63
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<Color4, Color3, Float>::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<float[3], Color3>::value);
CORRADE_VERIFY(!std::is_convertible<float[4], Color4>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Color3, float[3]>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Color4, float[4]>::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);

94
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<Matrix3, Float>::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<float[3][3], Matrix3>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Matrix3, float[3][3]>::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},

108
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<Matrix4, Float>::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<float[4][4], Matrix4>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Matrix4, float[4][4]>::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},

108
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<Matrix1x1, Vector1>::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<float[4][4], Matrix4x4>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Matrix4x4, float[4][4]>::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),

98
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<Matrix1x1, Vector1>::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<float[2][4], Matrix2x4>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Matrix2x4, float[2][4]>::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));

46
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<Vector2, Float>::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<float[2], Vector2>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Vector2, float[2]>::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);

47
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<Vector3, Vector2, Float>::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<float[3], Vector3>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Vector3, float[3]>::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);

47
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<Vector4, Vector3, Float>::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<float[4], Vector4>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Vector4, float[4]>::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);

63
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<Vector1, Float>::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<float[3], Vector3>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<Vector3, float[3]>::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);

26
src/Magnum/Math/Vector.h

@ -170,8 +170,9 @@ template<std::size_t size, class T> 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<size, T>& from(T* data) {
return *reinterpret_cast<Vector<size, T>*>(data);
@ -218,6 +219,24 @@ template<std::size_t size, class T> class Vector {
template<class ...U, class V = typename std::enable_if<sizeof...(U)+1 == size, T>::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<std::size_t size_> constexpr explicit Vector(const T(&data)[size_]) noexcept: Vector{typename Containers::Implementation::GenerateSequence<size_>::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<size>::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<std::size_t size, class T> class Vector {
template<std::size_t size_, class U> friend U dot(const Vector<size_, U>&, const Vector<size_, U>&);
/* Implementation for Vector<size, T>::Vector(const T(&data)[size_]) */
template<std::size_t ...sequence> constexpr explicit Vector(Containers::Implementation::Sequence<sequence...>, const T(&data)[sizeof...(sequence)]) noexcept: _data{data[sequence]...} {}
/* Implementation for Vector<size, T>::Vector(const Vector<size, U>&) */
template<class U, std::size_t ...sequence> constexpr explicit Vector(Containers::Implementation::Sequence<sequence...>, const Vector<size, U>& vector) noexcept: _data{T(vector._data[sequence])...} {}

8
src/Magnum/Math/Vector2.h

@ -138,6 +138,14 @@ template<class T> 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<std::size_t size_> 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<size, U>&) */
template<class U> constexpr explicit Vector2(const Vector<2, U>& other) noexcept: Vector<2, T>(other) {}

8
src/Magnum/Math/Vector3.h

@ -166,6 +166,14 @@ template<class T> class Vector3: public Vector<3, T> {
*/
constexpr /*implicit*/ Vector3(const Vector2<T>& 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<std::size_t size_> 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<size, U>&) */
template<class U> constexpr explicit Vector3(const Vector<3, U>& other) noexcept: Vector<3, T>(other) {}

11
src/Magnum/Math/Vector4.h

@ -108,6 +108,17 @@ template<class T> class Vector4: public Vector<4, T> {
*/
constexpr /*implicit*/ Vector4(const Vector3<T>& 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<std::size_t size_> 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<size, U>&) */
/* 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

Loading…
Cancel
Save