From d474f9d1761517a430cc9e615f549668e39c0de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 1 May 2022 14:03:32 +0200 Subject: [PATCH] Math: return an array reference instead of a pointer from data(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it possible to conveniently do things like Containers::StridedArrayView1D array = …; Vector4 vector{NoInit}; Utility::copy(array, vector); // or the other way around which is especially useful together with the new JSON classes. In some cases this means the function is no longer constexpr, but those weren't constexpr because it was useful for anything, they were only because it was possible. So this breakage shouldn't do any harm I think. --- doc/changelog.dox | 16 +++++++ src/Magnum/Math/Bezier.h | 15 ++++-- src/Magnum/Math/BoolVector.h | 15 ++++-- src/Magnum/Math/Complex.h | 26 ++++++++-- src/Magnum/Math/CubicHermite.h | 24 ++++++++-- src/Magnum/Math/Dual.h | 24 ++++++++-- src/Magnum/Math/DualComplex.h | 20 ++++++-- src/Magnum/Math/DualQuaternion.h | 20 ++++++-- src/Magnum/Math/Frustum.h | 30 ++++++++++-- src/Magnum/Math/Quaternion.h | 29 +++++++++-- src/Magnum/Math/Range.h | 40 +++++++++++----- src/Magnum/Math/RectangularMatrix.h | 30 ++++++++++-- src/Magnum/Math/Test/BezierTest.cpp | 13 +++-- src/Magnum/Math/Test/BoolVectorTest.cpp | 39 ++++++++------- src/Magnum/Math/Test/ComplexTest.cpp | 12 +++-- src/Magnum/Math/Test/CubicHermiteTest.cpp | 48 ++++++++++++------- src/Magnum/Math/Test/DualComplexTest.cpp | 12 +++-- src/Magnum/Math/Test/DualQuaternionTest.cpp | 15 +++--- src/Magnum/Math/Test/DualTest.cpp | 12 +++-- src/Magnum/Math/Test/FrustumTest.cpp | 31 ++++++++---- src/Magnum/Math/Test/QuaternionTest.cpp | 15 +++--- src/Magnum/Math/Test/RangeTest.cpp | 45 ++++++++++------- .../Math/Test/RectangularMatrixTest.cpp | 41 ++++++++-------- src/Magnum/Math/Test/VectorTest.cpp | 26 ++++++---- src/Magnum/Math/Vector.h | 15 ++++-- 25 files changed, 444 insertions(+), 169 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 63c66d743..18845eb04 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -385,6 +385,15 @@ See also: matrices, and with the default on @ref Math::RectangularMatrix being zero-fill while @ref Math::Matrix stays with the identity for consistency with other constructors. +- @ref Math::Bezier::data(), @ref Math::BoolVector::data(), + @ref Math::Complex::data(), @ref Math::CubicHermite::data(), + @ref Math::Dual::data(), @ref Math::DualComplex::data(), + @ref Math::DualQuaternion::data(), @ref Math::Frustum::data(), + @ref Math::Quaternion::data(), @ref Math::Range::data(), + @ref Math::RectangularMatrix::data() and @ref Math::Vector::data() now + return a reference to a fixed-size array instead of a pointer (i.e., + @cpp T(&)[size] @ce instead of @cpp T* @ce) for more convenient usage in + APIs that take sized views. @subsubsection changelog-latest-changes-meshtools MeshTools library @@ -946,6 +955,13 @@ See also: process. Existing code that calls these with unsanitized inputs now additionally needs to account for reflection as suggested in the documentation. +- @ref Math::Complex::data(), @ref Math::CubicHermite::data(), + @ref Math::Dual::data(), @ref Math::DualComplex::data(), + @ref Math::DualQuaternion::data(), @ref Math::Frustum::data(), + @ref Math::Quaternion::data(), @ref Math::Range::data() and + @ref Math::RectangularMatrix::data() are no longer @cpp constexpr @ce in + order to make them return a reference to a fixed-size array instead of a + pointer, which was deemed a more useful property. - @ref SceneGraph::Object::addChild() no longer requires the type constructor to have the last parameter a parent object object pointer, as that was quite limiting. Instead it's calling @ref SceneGraph::Object::setParent() diff --git a/src/Magnum/Math/Bezier.h b/src/Magnum/Math/Bezier.h index 2ed92f673..f2760997b 100644 --- a/src/Magnum/Math/Bezier.h +++ b/src/Magnum/Math/Bezier.h @@ -137,12 +137,21 @@ template class Bezier { /** * @brief Raw data - * @return One-dimensional array of @cpp order + 1 @ce elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of @cpp order + 1 @ce elements, + * i.e. @cpp T(&)[size] @ce. * @see @ref operator[]() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - Vector* data() { return _data; } - constexpr const Vector* data() const { return _data; } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Vector* data(); + constexpr const Vector* data() const; /**< @overload */ + #else + auto data() -> Vector(&)[order + 1] { return _data; } + constexpr auto data() const -> const Vector(&)[order + 1] { return _data; } + #endif /** @brief Equality comparison */ bool operator==(const Bezier& other) const { diff --git a/src/Magnum/Math/BoolVector.h b/src/Magnum/Math/BoolVector.h index 8badcbf7c..c9842d6fd 100644 --- a/src/Magnum/Math/BoolVector.h +++ b/src/Magnum/Math/BoolVector.h @@ -130,12 +130,21 @@ template class BoolVector { /** * @brief Raw data - * @return Array of DataSize length * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of @ref DataSize elements, i.e. + * @cpp UnsignedByte(&)[DataSize] @ce. * @see @ref operator[](), @ref set() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - UnsignedByte* data() { return _data; } - constexpr const UnsignedByte* data() const { return _data; } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + UnsignedByte* data(); + constexpr const UnsignedByte* data() const; /**< @overload */ + #else + auto data() -> UnsignedByte(&)[DataSize] { return _data; } + constexpr auto data() const -> const UnsignedByte(&)[DataSize] { return _data; } + #endif /** @brief Bit at given position */ constexpr bool operator[](std::size_t i) const { diff --git a/src/Magnum/Math/Complex.h b/src/Magnum/Math/Complex.h index 415315a2d..382186861 100644 --- a/src/Magnum/Math/Complex.h +++ b/src/Magnum/Math/Complex.h @@ -183,12 +183,30 @@ template class Complex { /** * @brief Raw data - * @return One-dimensional array of two elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of two elements, i.e. + * @cpp T(&)[2] @ce. * @see @ref real(), @ref imaginary() - */ - T* data() { return &_real; } - constexpr const T* data() const { return &_real; } /**< @overload */ + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[2] { + return reinterpret_cast(_real); + } + /* Can't be constexpr anymore, the only other solution would be to + store `T _data[2]` instead of the two variables, but that may make + the internal implementation too error prone. Similarly as with + RectangularMatrix::data(), having a statically sized array returned + is a far more useful property than constexpr, so that wins. */ + auto data() const -> const T(&)[2] { + return reinterpret_cast(_real); + } + #endif /** @brief Equality comparison */ bool operator==(const Complex& other) const { diff --git a/src/Magnum/Math/CubicHermite.h b/src/Magnum/Math/CubicHermite.h index b30b1053a..8878c0b9c 100644 --- a/src/Magnum/Math/CubicHermite.h +++ b/src/Magnum/Math/CubicHermite.h @@ -146,12 +146,30 @@ template class CubicHermite { /** * @brief Raw data - * @return One-dimensional array of three elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of three elements, i.e. + * @cpp T(&)[3] @ce. * @see @ref inTangent(), @ref point(), @ref outTangent() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return &_inTangent; } - constexpr const T* data() const { return &_inTangent; } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[3] { + return reinterpret_cast(_inTangent); + } + /* Can't be constexpr anymore, the only other solution would be to + store `T _data[3]` instead of the three variables, but that may make + the internal implementation too error prone. Similarly as with + RectangularMatrix::data(), having a statically sized array returned + is a far more useful property than constexpr, so that wins. */ + auto data() const -> const T(&)[3] { + return reinterpret_cast(_inTangent); + } + #endif /** @brief Equality comparison */ bool operator==(const CubicHermite& other) const; diff --git a/src/Magnum/Math/Dual.h b/src/Magnum/Math/Dual.h index ecac58ef1..fcf7594c8 100644 --- a/src/Magnum/Math/Dual.h +++ b/src/Magnum/Math/Dual.h @@ -113,12 +113,30 @@ template class Dual { /** * @brief Raw data - * @return One-dimensional array of two elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of two elements, i.e. + * @cpp T(&)[2] @ce. * @see @ref real(), @ref dual() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return &_real; } - constexpr const T* data() const { return &_real; } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[2] { + return reinterpret_cast(_real); + } + /* Can't be constexpr anymore, the only other solution would be to + store `T _data[2]` instead of the two variables, but that may make + the internal implementation too error prone. Similarly as with + RectangularMatrix::data(), having a statically sized array returned + is a far more useful property than constexpr, so that wins. */ + auto data() const -> const T(&)[2] { + return reinterpret_cast(_real); + } + #endif /** @brief Equality comparison */ bool operator==(const Dual& other) const { diff --git a/src/Magnum/Math/DualComplex.h b/src/Magnum/Math/DualComplex.h index bdbae24d6..76f229c81 100644 --- a/src/Magnum/Math/DualComplex.h +++ b/src/Magnum/Math/DualComplex.h @@ -191,12 +191,26 @@ template class DualComplex: public Dual> { /** * @brief Raw data - * @return One-dimensional array of four elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of four elements, i.e. + * @cpp T(&)[4] @ce. * @see @ref real(), @ref dual() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return Dual>::data()->data(); } - constexpr const T* data() const { return Dual>::data()->data(); } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[4] { + return reinterpret_cast(Dual>::data()); + } + /* Can't be constexpr anymore, see base implementation for details */ + auto data() const -> const T(&)[4] { + return reinterpret_cast(Dual>::data()); + } + #endif /** * @brief Whether the dual complex number is normalized diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index 54c01b9c7..417c99f67 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -338,12 +338,26 @@ template class DualQuaternion: public Dual> { /** * @brief Raw data - * @return One-dimensional array of eight elements * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of eight elements, i.e. + * @cpp T(&)[8] @ce. * @see @ref real(), @ref dual() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return Dual>::data()->data(); } - constexpr const T* data() const { return Dual>::data()->data(); } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[8] { + return reinterpret_cast(Dual>::data()); + } + /* Can't be constexpr anymore, see base implementation for details */ + auto data() const -> const T(&)[8] { + return reinterpret_cast(Dual>::data()); + } + #endif /** * @brief Whether the dual quaternion is normalized diff --git a/src/Magnum/Math/Frustum.h b/src/Magnum/Math/Frustum.h index 7a6ab145d..744275e8b 100644 --- a/src/Magnum/Math/Frustum.h +++ b/src/Magnum/Math/Frustum.h @@ -127,10 +127,34 @@ template class Frustum { /** * @brief Raw data - * @return One-dimensional array of length `24`. + * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of 24 elements, i.e. + * @cpp T(&)[24] @ce. + * @see @ref operator[]() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return _data[0].data(); } - constexpr const T* data() const { return _data[0].data(); } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[24] { + return reinterpret_cast(_data); + } + /* Can't really be constexpr anymore, the only other solution is having + an union with `T _rawData[24]` and return that, but in a constexpr + context it'd mean we'd have to initialize it instead of `_data` in + the constructor ... and then operator[]() could not be constexpr + anymore. I can't think of a practical use case where constexpr + data() would be needed and operator[]() could not be used instead. + Similarly to RectangularMatrix::data(), having a statically sized + array returned is a far more useful property than constexpr, so that + wins. */ + auto data() const -> const T(&)[24] { + return reinterpret_cast(_data); + } + #endif #ifdef MAGNUM_BUILD_DEPRECATED /** diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index 1cfac92ac..8ef1e333d 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -362,12 +362,33 @@ template class Quaternion { /** * @brief Raw data * - * Returns one-dimensional array of four elements, vector part first, - * scalar after. + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of four elements, i.e. + * @cpp T(&)[4] @ce, vector part first, scalar after. * @see @ref vector(), @ref scalar() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return _vector.data(); } - constexpr const T* data() const { return _vector.data(); } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[4] { + return reinterpret_cast(_vector); + } + /* Can't really be constexpr anymore, the only other solution is having + an union with `T _rawData[4]` and return that, but in a constexpr + context it'd mean we'd have to initialize it instead of `_data` in + the constructor ... and then operator[]() could not be constexpr + anymore. I can't think of a practical use case where constexpr + data() would be needed and operator[]() could not be used instead. + Similarly to RectangularMatrix::data(), having a statically sized + array returned is a far more useful property than constexpr, so that + wins. */ + auto data() const -> const T(&)[4] { + return reinterpret_cast(_vector); + } + #endif /** @brief Equality comparison */ bool operator==(const Quaternion& other) const { diff --git a/src/Magnum/Math/Range.h b/src/Magnum/Math/Range.h index e4ff9de90..2bccb0281 100644 --- a/src/Magnum/Math/Range.h +++ b/src/Magnum/Math/Range.h @@ -186,14 +186,34 @@ template class Range { /** * @brief Raw data - * @return One-dimensional array of `dimensions`*2 length. - */ - T* data() { - return dataInternal(typename std::conditional::type{}); + * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of @cpp dimensions*2 @ce elements, + * i.e. @cpp T(&)[dimensions*2] @ce. + * @ref min(), @ref max() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[dimensions*2] { + return reinterpret_cast(_min); + } + /* Can't really be constexpr anymore, the only other solution is having + an union with `T _rawData[24]` and return that, but in a constexpr + context it'd mean we'd have to initialize it instead of `_data` in + the constructor ... and then operator[]() could not be constexpr + anymore. I can't think of a practical use case where constexpr + data() would be needed and operator[]() could not be used instead. + Similarly to RectangularMatrix::data(), having a statically sized + array returned is a far more useful property than constexpr, so that + wins. */ + auto data() const -> const T(&)[dimensions*2] { + return reinterpret_cast(_min); } - constexpr const T* data() const { - return dataInternal(typename std::conditional::type{}); - } /**< @overload */ + #endif /** * @brief Minimal coordinates (inclusive) @@ -328,12 +348,6 @@ template class Range { explicit Range(Magnum::NoInitT, Magnum::NoInitT*) noexcept: _min{Magnum::NoInit}, _max{Magnum::NoInit} {} explicit Range(Magnum::NoInitT, void*) noexcept {} - /* Called from data(), always returning a T* */ - constexpr const VectorType* dataInternal(void*) const { return &_min; } - VectorType* dataInternal(void*) { return &_min; } - constexpr const T* dataInternal(T*) const { return _min.data(); } - T* dataInternal(T*) { return _min.data(); } - VectorType _min, _max; }; diff --git a/src/Magnum/Math/RectangularMatrix.h b/src/Magnum/Math/RectangularMatrix.h index 59ad03094..8d1c7cedf 100644 --- a/src/Magnum/Math/RectangularMatrix.h +++ b/src/Magnum/Math/RectangularMatrix.h @@ -218,13 +218,33 @@ template class RectangularMatrix { /** * @brief Raw data - * @return One-dimensional array of `cols*rows` length in column-major - * order. * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of @cpp cols*rows @ce elements, + * i.e. @cpp T(&)[cols*rows] @ce. * @see @ref operator[]() - */ - T* data() { return _data[0].data(); } - constexpr const T* data() const { return _data[0].data(); } /**< @overload */ + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[cols*rows] { + return reinterpret_cast(_data); + } + /* Can't really be constexpr anymore, the only other solution is having + an union with `T _rawData[cols*rows]` and return that, but in a + constexpr context it'd mean we'd have to initialize it instead of + `_data` in the constructor ... and then operator[]() could not be + constexpr anymore. I can't think of a practical use case where + constexpr data() would be needed and operator[]() could not be used + instead. Having a statically sized array returned is a far more + useful property than constexpr, so that wins. */ + auto data() const -> const T(&)[cols*rows] { + return reinterpret_cast(_data); + } + #endif /** * @brief Column at given position diff --git a/src/Magnum/Math/Test/BezierTest.cpp b/src/Magnum/Math/Test/BezierTest.cpp index 50424030c..488781b56 100644 --- a/src/Magnum/Math/Test/BezierTest.cpp +++ b/src/Magnum/Math/Test/BezierTest.cpp @@ -229,20 +229,23 @@ void BezierTest::data() { CORRADE_COMPARE(a[2], (Vector2{0.7f, 20.3f})); CORRADE_COMPARE(a, (QuadraticBezier2D{Vector2{0.0f, 0.0f}, Vector2{1.1f, 0.3f}, Vector2{0.7f, 20.3f}})); - constexpr QuadraticBezier2D b{Vector2{3.5f, 0.1f}, Vector2{1.3f, 10.3f}, Vector2{0.0f, -1.2f}}; + constexpr QuadraticBezier2D ca{Vector2{3.5f, 0.1f}, Vector2{1.3f, 10.3f}, Vector2{0.0f, -1.2f}}; #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Why? */ constexpr #endif - Vector2 c = b[2]; + Vector2 c = ca[2]; CORRADE_COMPARE(c, (Vector2{0.0f, -1.2f})); #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Why? */ constexpr #endif - Vector2 d = *b.data(); - Vector2 e = a.data()[2]; + Vector2 d = *ca.data(); + CORRADE_COMPARE(a.data()[2], (Vector2{0.7f, 20.3f})); CORRADE_COMPARE(d, (Vector2{3.5f, 0.1f})); - CORRADE_COMPARE(e, (Vector2{0.7f, 20.3f})); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void BezierTest::compare() { diff --git a/src/Magnum/Math/Test/BoolVectorTest.cpp b/src/Magnum/Math/Test/BoolVectorTest.cpp index 2db39fbe9..c2989348b 100644 --- a/src/Magnum/Math/Test/BoolVectorTest.cpp +++ b/src/Magnum/Math/Test/BoolVectorTest.cpp @@ -207,32 +207,37 @@ void BoolVectorTest::convert() { void BoolVectorTest::data() { /* 0b00001000, 0b00000011, 0b100 */ - constexpr BoolVector19 a(0x08, 0x03, 0x04); + constexpr BoolVector19 ca(0x08, 0x03, 0x04); - CORRADE_VERIFY(!a[0] && !a[1] && !a[2]); - CORRADE_VERIFY(a[3]); - CORRADE_VERIFY(!a[4] && !a[5] && !a[6] && !a[7]); - CORRADE_VERIFY(a[8]); - CORRADE_VERIFY(a[9]); - CORRADE_VERIFY(!a[10] && !a[11] && !a[12] && !a[13] && !a[14] && !a[15] && !a[16] && !a[17]); - CORRADE_VERIFY(a[18]); + CORRADE_VERIFY(!ca[0] && !ca[1] && !ca[2]); + CORRADE_VERIFY(ca[3]); + CORRADE_VERIFY(!ca[4] && !ca[5] && !ca[6] && !ca[7]); + CORRADE_VERIFY(ca[8]); + CORRADE_VERIFY(ca[9]); + CORRADE_VERIFY(!ca[10] && !ca[11] && !ca[12] && !ca[13] && !ca[14] && !ca[15] && !ca[16] && !ca[17]); + CORRADE_VERIFY(ca[18]); - constexpr bool b = a[9]; + constexpr bool b = ca[9]; CORRADE_COMPARE(b, true); + BoolVector19 a(0x08, 0x03, 0x04); + a.set(15, true); + CORRADE_VERIFY(a[15]); + CORRADE_COMPARE(a, BoolVector19(0x08, 0x83, 0x04)); + a.set(15, false); + CORRADE_VERIFY(!a[15]); + CORRADE_COMPARE(a, BoolVector19(0x08, 0x03, 0x04)); + #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing pointer is verboten */ constexpr #endif - UnsignedByte c = *a.data(); + UnsignedByte c = *ca.data(); + CORRADE_COMPARE(a.data()[1], 0x03); CORRADE_COMPARE(c, 0x08); - BoolVector19 d(0x08, 0x03, 0x04); - d.set(15, true); - CORRADE_VERIFY(d[15]); - CORRADE_COMPARE(d, BoolVector19(0x08, 0x83, 0x04)); - d.set(15, false); - CORRADE_VERIFY(!d[15]); - CORRADE_COMPARE(d, BoolVector19(0x08, 0x03, 0x04)); + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void BoolVectorTest::compare() { diff --git a/src/Magnum/Math/Test/ComplexTest.cpp b/src/Magnum/Math/Test/ComplexTest.cpp index c62f8cba8..0a2d09932 100644 --- a/src/Magnum/Math/Test/ComplexTest.cpp +++ b/src/Magnum/Math/Test/ComplexTest.cpp @@ -295,10 +295,14 @@ void ComplexTest::data() { a.imaginary() = -3.5f; CORRADE_COMPARE(a, (Complex{2.0f, -3.5f})); - constexpr Float b = *ca.data(); - Float c = a.data()[1]; - CORRADE_COMPARE(b, 1.5f); - CORRADE_COMPARE(c, -3.5f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[1], -3.5f); + CORRADE_COMPARE(*ca.data(), 1.5f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 2); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 2); } void ComplexTest::compare() { diff --git a/src/Magnum/Math/Test/CubicHermiteTest.cpp b/src/Magnum/Math/Test/CubicHermiteTest.cpp index 574ae5c6c..09d8b9dda 100644 --- a/src/Magnum/Math/Test/CubicHermiteTest.cpp +++ b/src/Magnum/Math/Test/CubicHermiteTest.cpp @@ -672,10 +672,14 @@ void CubicHermiteTest::dataScalar() { a.outTangent() = 2.1f; CORRADE_COMPARE(a, (CubicHermite1D{3.0f, 1.0f, 2.1f})); - constexpr Float b = *ca.data(); - Float c = a.data()[2]; - CORRADE_COMPARE(b, 2.0f); - CORRADE_COMPARE(c, 2.1f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(*ca.data(), 2.0f); + CORRADE_COMPARE(a.data()[2], 2.1f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void CubicHermiteTest::dataVector() { @@ -693,10 +697,14 @@ void CubicHermiteTest::dataVector() { a.outTangent().y() = 2.0f; CORRADE_COMPARE(a, (CubicHermite2D{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); - constexpr Vector2 b = *ca.data(); - Vector2 c = a.data()[2]; - CORRADE_COMPARE(b, (Vector2{1.0f, 2.0f})); - CORRADE_COMPARE(c, (Vector2{3.0f, 2.0f})); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[2], (Vector2{3.0f, 2.0f})); + CORRADE_COMPARE(*ca.data(), (Vector2{1.0f, 2.0f})); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void CubicHermiteTest::dataComplex() { @@ -714,10 +722,14 @@ void CubicHermiteTest::dataComplex() { a.outTangent().imaginary() = 2.0f; CORRADE_COMPARE(a, (CubicHermiteComplex{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); - constexpr Complex b = *ca.data(); - Complex c = a.data()[2]; - CORRADE_COMPARE(b, (Complex{1.0f, 2.0f})); - CORRADE_COMPARE(c, (Complex{3.0f, 2.0f})); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[2], (Complex{3.0f, 2.0f})); + CORRADE_COMPARE(*ca.data(), (Complex{1.0f, 2.0f})); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void CubicHermiteTest::dataQuaternion() { @@ -745,10 +757,14 @@ void CubicHermiteTest::dataQuaternion() { {{1.5f, -2.0f, 0.1f}, 1.0f}, {{3.0f, -0.5f, 2.0f}, 0.3f}})); - constexpr Quaternion b = *ca.data(); - Quaternion c = a.data()[2]; - CORRADE_COMPARE(b, (Quaternion{{1.0f, 2.0f, -1.0f}, 3.0f})); - CORRADE_COMPARE(c, (Quaternion{{3.0f, -0.5f, 2.0f}, 0.3f})); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[2], (Quaternion{{3.0f, -0.5f, 2.0f}, 0.3f})); + CORRADE_COMPARE(*ca.data(), (Quaternion{{1.0f, 2.0f, -1.0f}, 3.0f})); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 3); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 3); } void CubicHermiteTest::compareScalar() { diff --git a/src/Magnum/Math/Test/DualComplexTest.cpp b/src/Magnum/Math/Test/DualComplexTest.cpp index cb24a3841..4aab835e4 100644 --- a/src/Magnum/Math/Test/DualComplexTest.cpp +++ b/src/Magnum/Math/Test/DualComplexTest.cpp @@ -288,10 +288,14 @@ void DualComplexTest::data() { DualComplex a{{-1.0f, 2.5f}, {3.0f, -7.5f}}; - constexpr Float d = *ca.data(); - Float e = a.data()[3]; - CORRADE_COMPARE(d, -1.0f); - CORRADE_COMPARE(e, -7.5f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(*ca.data(), -1.0f); + CORRADE_COMPARE(a.data()[3], -7.5f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 4); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 4); } void DualComplexTest::isNormalized() { diff --git a/src/Magnum/Math/Test/DualQuaternionTest.cpp b/src/Magnum/Math/Test/DualQuaternionTest.cpp index 43187f1c4..80c84f10f 100644 --- a/src/Magnum/Math/Test/DualQuaternionTest.cpp +++ b/src/Magnum/Math/Test/DualQuaternionTest.cpp @@ -322,13 +322,14 @@ void DualQuaternionTest::data() { DualQuaternion a{{{1.0f, 2.0f, 3.0f}, -4.0f}, {{0.5f, -3.1f, 3.3f}, 2.0f}}; - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing a pointer is verboten */ - constexpr - #endif - Float d = *ca.data(); - Float e = a.data()[7]; - CORRADE_COMPARE(d, 1.0f); - CORRADE_COMPARE(e, 2.0f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[7], 2.0f); + CORRADE_COMPARE(ca.data()[4], 0.5f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 8); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 8); } void DualQuaternionTest::isNormalized() { diff --git a/src/Magnum/Math/Test/DualTest.cpp b/src/Magnum/Math/Test/DualTest.cpp index cada3a1ce..5bbde26c0 100644 --- a/src/Magnum/Math/Test/DualTest.cpp +++ b/src/Magnum/Math/Test/DualTest.cpp @@ -208,10 +208,14 @@ void DualTest::data() { a.dual() = -3.5f; CORRADE_COMPARE(a, (Dual{2.0f, -3.5f})); - constexpr Float b = *ca.data(); - Float c = a.data()[1]; - CORRADE_COMPARE(b, 1.5f); - CORRADE_COMPARE(c, -3.5f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(*ca.data(), 1.5f); + CORRADE_COMPARE(a.data()[1], -3.5f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 2); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 2); } void DualTest::compare() { diff --git a/src/Magnum/Math/Test/FrustumTest.cpp b/src/Magnum/Math/Test/FrustumTest.cpp index decaef02f..8bea6e78f 100644 --- a/src/Magnum/Math/Test/FrustumTest.cpp +++ b/src/Magnum/Math/Test/FrustumTest.cpp @@ -310,31 +310,42 @@ void FrustumTest::convert() { void FrustumTest::data() { /* Using default-constructed to verify that the planes are in correct order */ - constexpr Frustum a; + constexpr Frustum ca; #if !defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5 constexpr #endif - Vector4 right = a.cbegin()[1]; + Vector4 right = ca.cbegin()[1]; CORRADE_COMPARE(right, (Vector4{-1.0f, 0.0f, 0.0f, 1.0f})); - constexpr Vector4 bottom = a[2]; + constexpr Vector4 bottom = ca[2]; CORRADE_COMPARE(bottom, (Vector4{0.0f, 1.0f, 0.0f, 1.0f})); - constexpr Vector4 near = a.near(); + constexpr Vector4 near = ca.near(); CORRADE_COMPARE(near, (Vector4{0.0f, 0.0f, 1.0f, 1.0f})); #if !defined(CORRADE_MSVC2015_COMPATIBILITY) && (!defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG) || __GNUC__ >= 5) constexpr #endif - Vector4 far = *(a.cend() - 1); + Vector4 far = *(ca.cend() - 1); CORRADE_COMPARE(far, (Vector4{0.0f, 0.0f, -1.0f, 1.0f})); - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing pointer is verboten */ - constexpr - #endif - Float b = *a.data(); - CORRADE_COMPARE(b, 1.0f); + constexpr Frustum a{ + {-1.0f, 2.0f, -3.0f, 0.1f}, + { 1.0f, -2.0f, 3.0f, 0.2f}, + {-4.0f, 5.0f, -6.0f, 0.3f}, + { 4.0f, -5.0f, 6.0f, 0.4f}, + {-7.0f, 8.0f, -9.0f, 0.5f}, + { 7.0f, 8.0f, 9.0f, 0.6f}}; + + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[9], 5.0f); + CORRADE_COMPARE(ca.data()[4], -1.0f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 24); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 24); } void FrustumTest::dataOutOfRange() { diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index 54e575052..4b36c918e 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -334,13 +334,14 @@ void QuaternionTest::data() { a.scalar() = 1.1f; CORRADE_COMPARE(a, (Quaternion{{1.0f, 4.3f, 3.0f}, 1.1f})); - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing a pointer is verboten */ - constexpr - #endif - Float b = *ca.data(); - Float c = a.data()[3]; - CORRADE_COMPARE(b, 1.0f); - CORRADE_COMPARE(c, 1.1f); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[3], 1.1f); + CORRADE_COMPARE(ca.data()[1], 2.0f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 4); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 4); } void QuaternionTest::compare() { diff --git a/src/Magnum/Math/Test/RangeTest.cpp b/src/Magnum/Math/Test/RangeTest.cpp index 7ae8394aa..f2c953f46 100644 --- a/src/Magnum/Math/Test/RangeTest.cpp +++ b/src/Magnum/Math/Test/RangeTest.cpp @@ -111,6 +111,7 @@ struct RangeTest: Corrade::TestSuite::Tester { void constructCopy(); void convert(); + void data(); void access(); void compare(); void dimensionSlice(); @@ -167,6 +168,7 @@ RangeTest::RangeTest() { &RangeTest::constructCopy, &RangeTest::convert, + &RangeTest::data, &RangeTest::access, &RangeTest::compare, &RangeTest::dimensionSlice, @@ -425,7 +427,7 @@ void RangeTest::convert() { CORRADE_VERIFY(!std::is_convertible::value); } -void RangeTest::access() { +void RangeTest::data() { Range1Di line(34, 47); Range2Di rect({34, 23}, {47, 30}); Range3Di cube({34, 23, -17}, {47, 30, 12}); @@ -434,21 +436,32 @@ void RangeTest::access() { constexpr Range2Di crect({34, 23}, {47, 30}); constexpr Range3Di ccube({34, 23, -17}, {47, 30, 12}); - CORRADE_COMPARE(line.data(), static_cast(&line)); - CORRADE_COMPARE(rect.data(), static_cast(&rect)); - CORRADE_COMPARE(cube.data(), static_cast(&cube)); - constexpr Int lineData = *cline.data(); - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing a pointer is verboten */ - constexpr - #endif - Int rectData = *crect.data(); - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing a pointer is verboten */ - constexpr - #endif - Int cubeData = *ccube.data(); - CORRADE_COMPARE(lineData, 34); - CORRADE_COMPARE(rectData, 34); - CORRADE_COMPARE(cubeData, 34); + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(line.data()[1], 47); + CORRADE_COMPARE(cline.data()[1], 47); + CORRADE_COMPARE(*rect.data(), 34); + CORRADE_COMPARE(*crect.data(), 34); + CORRADE_COMPARE(cube.data()[2], -17); + CORRADE_COMPARE(ccube.data()[2], -17); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(line.data()), 2); + CORRADE_COMPARE(Corrade::Containers::arraySize(cline.data()), 2); + CORRADE_COMPARE(Corrade::Containers::arraySize(rect.data()), 4); + CORRADE_COMPARE(Corrade::Containers::arraySize(crect.data()), 4); + CORRADE_COMPARE(Corrade::Containers::arraySize(cube.data()), 6); + CORRADE_COMPARE(Corrade::Containers::arraySize(ccube.data()), 6); +} + +void RangeTest::access() { + Range1Di line(34, 47); + Range2Di rect({34, 23}, {47, 30}); + Range3Di cube({34, 23, -17}, {47, 30, 12}); + + constexpr Range1Di cline(34, 47); + constexpr Range2Di crect({34, 23}, {47, 30}); + constexpr Range3Di ccube({34, 23, -17}, {47, 30, 12}); CORRADE_COMPARE(line.min(), 34); CORRADE_COMPARE(cline.min(), 34); diff --git a/src/Magnum/Math/Test/RectangularMatrixTest.cpp b/src/Magnum/Math/Test/RectangularMatrixTest.cpp index 149dbb6ee..b468156f8 100644 --- a/src/Magnum/Math/Test/RectangularMatrixTest.cpp +++ b/src/Magnum/Math/Test/RectangularMatrixTest.cpp @@ -402,37 +402,40 @@ void RectangularMatrixTest::convert() { } void RectangularMatrixTest::data() { - Matrix3x4 m; + Matrix3x4 a; Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); - m[2] = vector; - m[1][1] = 1.0f; - m[0][2] = 1.5f; + a[2] = vector; + a[1][1] = 1.0f; + a[0][2] = 1.5f; - CORRADE_COMPARE(m[1][1], 1.0f); - CORRADE_COMPARE(m[0][2], 1.5f); - CORRADE_COMPARE(m[2], vector); + CORRADE_COMPARE(a[1][1], 1.0f); + CORRADE_COMPARE(a[0][2], 1.5f); + CORRADE_COMPARE(a[2], vector); - CORRADE_COMPARE(m, Matrix3x4(Vector4(0.0f, 0.0f, 1.5f, 0.0f), + CORRADE_COMPARE(a, Matrix3x4(Vector4(0.0f, 0.0f, 1.5f, 0.0f), Vector4(0.0f, 1.0f, 0.0f, 0.0f), Vector4(4.0f, 5.0f, 6.0f, 7.0f))); - /* Pointer chasings, i.e. *(b.data()[1]), are not possible */ - constexpr Matrix3x4 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f), - Vector4(4.5f, 4.0f, 7.0f, 3.0f), - Vector4(7.0f, -1.7f, 8.0f, 0.0f)); + constexpr Matrix3x4 ca(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.5f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.7f, 8.0f, 0.0f)); #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Probably because copy is not constexpr */ constexpr #endif - Vector4 b = a[2]; - constexpr Float c = a[1][2]; - #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing pointer is verboten */ - constexpr - #endif - Float d = *a.data(); + Vector4 b = ca[2]; + constexpr Float c = ca[1][2]; CORRADE_COMPARE(b, Vector4(7.0f, -1.7f, 8.0f, 0.0f)); CORRADE_COMPARE(c, 7.0f); - CORRADE_COMPARE(d, 3.0f); + + /* Not constexpr anymore, as it has to reinterpret to return a + correctly-sized array */ + CORRADE_COMPARE(a.data()[8], 4.0f); + CORRADE_COMPARE(ca.data()[1], 5.0f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 12); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 12); } void RectangularMatrixTest::row() { diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index 23450bdfc..e79c695c1 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -341,23 +341,29 @@ void VectorTest::isNormalized() { } void VectorTest::data() { - Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); - vector[2] = 1.0f; - vector[3] = 1.5f; + Vector4 a(4.0f, 5.0f, 6.0f, 7.0f); + a[2] = 1.0f; + a[3] = 1.5f; - CORRADE_COMPARE(vector[2], 1.0f); - CORRADE_COMPARE(vector[3], 1.5f); - CORRADE_COMPARE(vector, Vector4(4.0f, 5.0f, 1.0f, 1.5f)); + CORRADE_COMPARE(a[2], 1.0f); + CORRADE_COMPARE(a[3], 1.5f); + CORRADE_COMPARE(a, Vector4(4.0f, 5.0f, 1.0f, 1.5f)); + + constexpr Vector4 ca(1.0f, 2.0f, -3.0f, 4.5f); + constexpr Float f = ca[3]; + CORRADE_COMPARE(f, 4.5f); /* Pointer chasings, i.e. *(b.data()[3]), are not possible */ - constexpr Vector4 a(1.0f, 2.0f, -3.0f, 4.5f); - constexpr Float f = a[3]; #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Apparently dereferencing a pointer is verboten */ constexpr #endif - Float g = *a.data(); - CORRADE_COMPARE(f, 4.5f); + Float g = *ca.data(); + CORRADE_COMPARE(a.data()[1], 5.0f); CORRADE_COMPARE(g, 1.0f); + + /* It actually returns an array */ + CORRADE_COMPARE(Corrade::Containers::arraySize(a.data()), 4); + CORRADE_COMPARE(Corrade::Containers::arraySize(ca.data()), 4); } void VectorTest::compare() { diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 57d3ec4e6..1f13f6c05 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -233,12 +233,21 @@ template class Vector { /** * @brief Raw data - * @return One-dimensional array of `size` length. * + * Contrary to what Doxygen shows, returns reference to an + * one-dimensional fixed-size array of `size` elements, i.e. + * @cpp T(&)[size] @ce. * @see @ref operator[]() + * @todoc Fix once there's a possibility to patch the signature in a + * post-processing step (https://github.com/mosra/m.css/issues/56) */ - T* data() { return _data; } - constexpr const T* data() const { return _data; } /**< @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + T* data(); + constexpr const T* data() const; /**< @overload */ + #else + auto data() -> T(&)[size] { return _data; } + constexpr auto data() const -> const T(&)[size] { return _data; } + #endif /** * @brief Value at given position