From e0909fedfe465ccb0628d11af442c8e15cd040d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 17 May 2022 15:49:51 +0200 Subject: [PATCH] Math: add castInto() variants for Double<->integer. Because yes of course dealing with a JSON just isn't possible without having to make decisions between insufficiently imprecise integers and unnecessarly overprecise doubles. --- doc/changelog.dox | 4 +- src/Magnum/Math/PackingBatch.cpp | 48 +++++++++++ src/Magnum/Math/PackingBatch.h | 100 ++++++++++++++++++++++ src/Magnum/Math/Test/PackingBatchTest.cpp | 96 ++++++++++++--------- 4 files changed, 204 insertions(+), 44 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 2dda148bc..0052d95bf 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -379,8 +379,8 @@ See also: - Added @ref Math::castInto() overloads for casting between @ref UnsignedByte and @ref UnsignedShort or @ref Byte and @ref Short, from and to - @ref UnsignedLong / @ref Long, and for casting between @ref Float and - @ref Double + @ref UnsignedLong / @ref Long, between integral types and @ref Double and + for casting between @ref Float and @ref Double - @ref Math::RectangularMatrix is now explicitly convertible from matrices of different sizes, with a possibility to specify whether to fill the diagonal or leave it as zeros. This was originally available only on (square) diff --git a/src/Magnum/Math/PackingBatch.cpp b/src/Magnum/Math/PackingBatch.cpp index a72042595..57a59798e 100644 --- a/src/Magnum/Math/PackingBatch.cpp +++ b/src/Magnum/Math/PackingBatch.cpp @@ -216,6 +216,30 @@ void castInto(const Corrade::Containers::StridedArrayView2D& src, con castIntoImplementation(src, dst); } +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } @@ -240,6 +264,30 @@ void castInto(const Corrade::Containers::StridedArrayView2D& src, c castIntoImplementation(src, dst); } +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } diff --git a/src/Magnum/Math/PackingBatch.h b/src/Magnum/Math/PackingBatch.h index ce5d76021..403c817b4 100644 --- a/src/Magnum/Math/PackingBatch.h +++ b/src/Magnum/Math/PackingBatch.h @@ -215,6 +215,56 @@ MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); +/** +@brief Cast integer values into a 64-bit floating-point representation +@param[in] src Source integral values +@param[out] dst Destination float values +@m_since_latest + +Unlike @ref packInto(), this function performs only an equivalent of +@cpp Double(a) @ce over the range, so e.g. @cpp 135 @ce becomes @cpp 135.0 @ce. +Second dimension is meant to contain vector/matrix components, or have a size +of 1 for scalars. Expects that @p src and @p dst have the same size and that +the second dimension in both is contiguous. + +@attention Numbers with more than 52 bits of precision will not be represented + accurately when cast into a @relativeref{Magnum,Double}. + +@see @ref castInto(const Corrade::Containers::StridedArrayView2D&, const Corrade::Containers::StridedArrayView2D&), + @ref Corrade::Containers::StridedArrayView::isContiguous() +*/ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + /** @brief Cast 32-bit floating-point values into an integer representation @param[in] src Source float values @@ -265,6 +315,56 @@ MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); +/** +@brief Cast 64-bit floating-point values into an integer representation +@param[in] src Source double values +@param[out] dst Destination integral values +@m_since_latest + +Unlike @ref packInto(), this function performs only an equivalent of +@cpp T(a) @ce over the range, so e.g. @cpp 135.0 @ce becomes @cpp 135 @ce. +Second dimension is meant to contain vector/matrix components, or have a size +of 1 for scalars. Expects that @p src and @p dst have the same size and that +the second dimension in both is contiguous. + +@attention Fractional part of the @relativeref{Magnum,Double} input will be + silently discarded when cast into an integer type. + +@see @ref castInto(const Corrade::Containers::StridedArrayView2D&, const Corrade::Containers::StridedArrayView2D&), + @ref Corrade::Containers::StridedArrayView::isContiguous() +*/ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + /** @brief Cast integer values into a differently sized type @param[in] src Source values diff --git a/src/Magnum/Math/Test/PackingBatchTest.cpp b/src/Magnum/Math/Test/PackingBatchTest.cpp index d5828f6f8..641efa867 100644 --- a/src/Magnum/Math/Test/PackingBatchTest.cpp +++ b/src/Magnum/Math/Test/PackingBatchTest.cpp @@ -51,8 +51,8 @@ struct PackingBatchTest: Corrade::TestSuite::Tester { void unpackHalf(); void packHalf(); - template void castUnsignedFloat(); - template void castSignedFloat(); + template void castUnsignedFloatingPoint(); + template void castSignedFloatingPoint(); template void castUnsignedInteger(); template void castSignedInteger(); @@ -77,12 +77,18 @@ PackingBatchTest::PackingBatchTest() { &PackingBatchTest::unpackHalf, &PackingBatchTest::packHalf, - &PackingBatchTest::castUnsignedFloat, - &PackingBatchTest::castUnsignedFloat, - &PackingBatchTest::castUnsignedFloat, - &PackingBatchTest::castSignedFloat, - &PackingBatchTest::castSignedFloat, - &PackingBatchTest::castSignedFloat, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castUnsignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, + &PackingBatchTest::castSignedFloatingPoint, &PackingBatchTest::castUnsignedInteger, &PackingBatchTest::castUnsignedInteger, @@ -109,6 +115,12 @@ PackingBatchTest::PackingBatchTest() { &PackingBatchTest::assertionsCast, &PackingBatchTest::assertionsCast, &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, &PackingBatchTest::assertionsCast, &PackingBatchTest::assertionsCast, &PackingBatchTest::assertionsCast, @@ -433,12 +445,12 @@ void PackingBatchTest::packHalf() { CORRADE_COMPARE(Math::packHalf(data[i].src), data[i].dst); } -template void PackingBatchTest::castUnsignedFloat() { - setTestCaseTemplateName(TypeTraits::name()); +template void PackingBatchTest::castUnsignedFloatingPoint() { + setTestCaseTemplateName({TypeTraits::name(), TypeTraits::name()}); struct Data { - Math::Vector2 src; - Vector2 dst; + Math::Vector2 src; + Math::Vector2 dst; } data[]{ {{0, 89}, {}}, {{149, 22}, {}}, @@ -447,38 +459,38 @@ template void PackingBatchTest::castUnsignedFloat() { /* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type ‘const Vector2 [3]’ with a compound literal), wtf */ - const Vector2 expectedFloat[] { - {0.0f, 89.0f}, - {149.0f, 22.0f}, - {13.0f, 255.0f} + const Math::Vector2 expectedFloatingPoint[] { + {FloatingPoint(0.0), FloatingPoint(89.0)}, + {FloatingPoint(149.0), FloatingPoint(22.0)}, + {FloatingPoint(13.0), FloatingPoint(255.0)} }; - constexpr Math::Vector2 expectedInteger[] { + constexpr Math::Vector2 expectedIntegral[] { {0, 89}, {149, 22}, {13, 255} }; - Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; - Corrade::Containers::StridedArrayView1D dst{data, &data[0].dst, 3, sizeof(Data)}; - castInto(Corrade::Containers::arrayCast<2, T>(src), - Corrade::Containers::arrayCast<2, Float>(dst)); - CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloat), + Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; + Corrade::Containers::StridedArrayView1D> dst{data, &data[0].dst, 3, sizeof(Data)}; + castInto(Corrade::Containers::arrayCast<2, Integral>(src), + Corrade::Containers::arrayCast<2, FloatingPoint>(dst)); + CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloatingPoint), Corrade::TestSuite::Compare::Container); /* Test the other way around as well */ - castInto(Corrade::Containers::arrayCast<2, Float>(dst), - Corrade::Containers::arrayCast<2, T>(src)); - CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedInteger), + castInto(Corrade::Containers::arrayCast<2, FloatingPoint>(dst), + Corrade::Containers::arrayCast<2, Integral>(src)); + CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedIntegral), Corrade::TestSuite::Compare::Container); } -template void PackingBatchTest::castSignedFloat() { - setTestCaseTemplateName(TypeTraits::name()); +template void PackingBatchTest::castSignedFloatingPoint() { + setTestCaseTemplateName({TypeTraits::name(), TypeTraits::name()}); struct Data { - Math::Vector2 src; - Vector2 dst; + Math::Vector2 src; + Math::Vector2 dst; } data[]{ {{0, -89}, {}}, {{-119, 22}, {}}, @@ -487,29 +499,29 @@ template void PackingBatchTest::castSignedFloat() { /* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type ‘const Vector2 [3]’ with a compound literal), wtf */ - const Vector2 expectedFloat[] { - {0.0f, -89.0f}, - {-119.0f, 22.0f}, - {13.0f, 127.0f} + const Math::Vector2 expectedFloatingPoint[] { + {FloatingPoint(0.0), FloatingPoint(-89.0)}, + {FloatingPoint(-119.0), FloatingPoint(22.0)}, + {FloatingPoint(13.0), FloatingPoint(127.0)} }; - constexpr Math::Vector2 expectedInteger[] { + constexpr Math::Vector2 expectedIntegral[] { {0, -89}, {-119, 22}, {13, 127} }; - Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; - Corrade::Containers::StridedArrayView1D dst{data, &data[0].dst, 3, sizeof(Data)}; - castInto(Corrade::Containers::arrayCast<2, T>(src), - Corrade::Containers::arrayCast<2, Float>(dst)); - CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloat), + Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; + Corrade::Containers::StridedArrayView1D> dst{data, &data[0].dst, 3, sizeof(Data)}; + castInto(Corrade::Containers::arrayCast<2, Integral>(src), + Corrade::Containers::arrayCast<2, FloatingPoint>(dst)); + CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloatingPoint), Corrade::TestSuite::Compare::Container); /* Test the other way around as well */ - castInto(Corrade::Containers::arrayCast<2, Float>(dst), - Corrade::Containers::arrayCast<2, T>(src)); - CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedInteger), + castInto(Corrade::Containers::arrayCast<2, FloatingPoint>(dst), + Corrade::Containers::arrayCast<2, Integral>(src)); + CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedIntegral), Corrade::TestSuite::Compare::Container); }