diff --git a/impl/ocean/base/Frame.h b/impl/ocean/base/Frame.h index 61b3bfa90..36c8307b2 100644 --- a/impl/ocean/base/Frame.h +++ b/impl/ocean/base/Frame.h @@ -1729,6 +1729,22 @@ class OCEAN_BASE_EXPORT FrameType */ static const FrameType::PixelFormats& definedPixelFormats(); + /** + * Returns whether two values can be added with each other without producing an overflow. + * @param valueA The first value to add + * @param valueB The second value to add + * @return True, if the sum is within a valid value range + */ + static constexpr bool isSumInsideValueRange(const unsigned int valueA, const unsigned int valueB); + + /** + * Returns whether two values can be multiplied with each other without producing an overflow. + * @param valueA The first value to multiply + * @param valueB The second value to multiply + * @return True, if the product is within a valid value range + */ + static constexpr bool isProductInsideValueRange(const unsigned int valueA, const unsigned int valueB); + private: /// Frame width in pixel, with range [0, infinity) @@ -2923,7 +2939,7 @@ class OCEAN_BASE_EXPORT Frame : public FrameType /** * Returns whether this frame is valid. - * This function is mainly callying `FrameType::isValid()`, while in debug builds, addtional checks are performed. + * This function is mainly calling `FrameType::isValid()`, while in debug builds, additional checks are performed. * @return True, if so */ inline bool isValid() const; @@ -3473,6 +3489,16 @@ inline bool FrameType::dataIsAligned(const void* data) return size_t(data) % sizeof(T) == size_t(0); } +constexpr bool FrameType::isSumInsideValueRange(const unsigned int valueA, const unsigned int valueB) +{ + return valueA <= (unsigned int)(-1) - valueB; +} + +constexpr bool FrameType::isProductInsideValueRange(const unsigned int valueA, const unsigned int valueB) +{ + return valueB == 0u || valueA <= (unsigned int)(-1) / valueB; +} + inline Frame::Plane::Plane(Plane&& plane) noexcept { *this = std::move(plane); diff --git a/impl/ocean/test/testbase/TestFrame.cpp b/impl/ocean/test/testbase/TestFrame.cpp index c6c09a497..fbb1e4488 100644 --- a/impl/ocean/test/testbase/TestFrame.cpp +++ b/impl/ocean/test/testbase/TestFrame.cpp @@ -45,6 +45,18 @@ bool TestFrame::test(const double testDuration) Log::info() << "-"; Log::info() << " "; + allSucceeded = testIsSumInsideValueRange(testDuration) && allSucceeded; + + Log::info() << " "; + Log::info() << "-"; + Log::info() << " "; + + allSucceeded = testIsProductInsideValueRange(testDuration) && allSucceeded; + + Log::info() << " "; + Log::info() << "-"; + Log::info() << " "; + allSucceeded = testPlaneContructors(testDuration) && allSucceeded; Log::info() << " "; @@ -241,6 +253,16 @@ TEST(TestFrame, DefinedPixelFormats) EXPECT_TRUE(TestFrame::testDefinedPixelFormats()); } +TEST(TestFrame, IsSumInsideValueRange) +{ + EXPECT_TRUE(TestFrame::testIsSumInsideValueRange(GTEST_TEST_DURATION)); +} + +TEST(TestFrame, IsProductInsideValueRange) +{ + EXPECT_TRUE(TestFrame::testIsProductInsideValueRange(GTEST_TEST_DURATION)); +} + TEST(TestFrame, PlaneContructors) { EXPECT_TRUE(TestFrame::testPlaneContructors(GTEST_TEST_DURATION)); @@ -455,6 +477,119 @@ bool TestFrame::testDefinedPixelFormats() return allSucceeded; } +bool TestFrame::testIsSumInsideValueRange(const double testDuration) +{ + ocean_assert(testDuration > 0.0); + + Log::info() << "Testing Sum Inside Value range:"; + + RandomGenerator randomGenerator; + + Validation validation(randomGenerator); + + const Timestamp startTimestamp(true); + + do + { + const unsigned int valueA = (unsigned int)(RandomI::random32(randomGenerator)); + + const unsigned int valueB = (unsigned int)(RandomI::random32(randomGenerator)); + + const bool result = FrameType::isSumInsideValueRange(valueA, valueB); + + constexpr unsigned int maxValue = (unsigned int)(-1); + constexpr unsigned int maxValue_2 = maxValue / 2u; + static_assert(maxValue_2 * 2u == (unsigned int)(-2)); + + if (valueA <= maxValue_2 && valueB <= maxValue_2) + { + OCEAN_EXPECT_TRUE(validation, result); + } + else + { + if (valueA >= valueB) + { + const unsigned int remaining = maxValue - valueA; + + if (valueB <= remaining) + { + OCEAN_EXPECT_TRUE(validation, result); + } + else + { + OCEAN_EXPECT_FALSE(validation, result); + } + } + else + { + const unsigned int remaining = maxValue - valueB; + + if (valueA <= remaining) + { + OCEAN_EXPECT_TRUE(validation, result); + } + else + { + OCEAN_EXPECT_FALSE(validation, result); + } + } + } + } + while (!startTimestamp.hasTimePassed(testDuration)); + + Log::info() << "Validation: " << validation; + + return validation.succeeded(); +} + +bool TestFrame::testIsProductInsideValueRange(const double testDuration) +{ + ocean_assert(testDuration > 0.0); + + Log::info() << "Testing Product Inside Value range:"; + + RandomGenerator randomGenerator; + + Validation validation(randomGenerator); + + const Timestamp startTimestamp(true); + + do + { + const unsigned int valueA = (unsigned int)(RandomI::random32(randomGenerator)); + + const unsigned int valueB = (unsigned int)(RandomI::random32(randomGenerator)); + + const bool result = FrameType::isProductInsideValueRange(valueA, valueB); + + constexpr unsigned int maxValue = (unsigned int)(-1); + constexpr unsigned int maxSqrFactor = 65535u; + + if (valueA <= maxSqrFactor && valueB <= maxSqrFactor) + { + OCEAN_EXPECT_TRUE(validation, result); + } + + static_assert(sizeof(unsigned int) == sizeof(uint32_t)); + + const uint64_t product64 = uint64_t(valueA) * uint64_t(valueB); + + if (product64 <= uint64_t(maxValue)) + { + OCEAN_EXPECT_TRUE(validation, result); + } + else + { + OCEAN_EXPECT_FALSE(validation, result); + } + } + while (!startTimestamp.hasTimePassed(testDuration)); + + Log::info() << "Validation: " << validation; + + return validation.succeeded(); +} + bool TestFrame::testPlaneContructors(const double testDuration) { ocean_assert(testDuration > 0.0); diff --git a/impl/ocean/test/testbase/TestFrame.h b/impl/ocean/test/testbase/TestFrame.h index 2c1e930e5..2526dc59d 100644 --- a/impl/ocean/test/testbase/TestFrame.h +++ b/impl/ocean/test/testbase/TestFrame.h @@ -49,6 +49,20 @@ class OCEAN_TEST_BASE_EXPORT TestFrame */ static bool testDefinedPixelFormats(); + /** + * Sets the is sum inside value range functions. + * @param testDuration Number of seconds for each test, with range (0, infinity) + * @return True, if succeeded + */ + static bool testIsSumInsideValueRange(const double testDuration); + + /** + * Sets the is product inside value range functions. + * @param testDuration Number of seconds for each test, with range (0, infinity) + * @return True, if succeeded + */ + static bool testIsProductInsideValueRange(const double testDuration); + /** * Tests the Plane constructors. * @param testDuration Number of seconds for each test, with range (0, infinity)