Skip to content

Commit

Permalink
Added new helper functions to FrameType
Browse files Browse the repository at this point in the history
Summary:
The new helper function allow to determine whether a sum or product will be out of value range.
Added a corresponding unit test.

Reviewed By: enpe

Differential Revision: D68121394

fbshipit-source-id: 9cfd10cfc765a9ad530e35413c9019f83951cd79
  • Loading branch information
janherling authored and facebook-github-bot committed Jan 14, 2025
1 parent eb2360f commit 2353c95
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 1 deletion.
28 changes: 27 additions & 1 deletion impl/ocean/base/Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
135 changes: 135 additions & 0 deletions impl/ocean/test/testbase/TestFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() << " ";
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions impl/ocean/test/testbase/TestFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 2353c95

Please sign in to comment.