From 4c83c05b48d5f84520cdece992ac3fa5634a3c44 Mon Sep 17 00:00:00 2001 From: philipel Date: Mon, 14 Mar 2016 08:43:35 -0700 Subject: [PATCH] Implemented more general version of ForwardDiff/RevereseDiff. In this CL: - Added more general version of ForwardDiff/RevereseDiff. - Replaced macro for testing if type T is of unsiged int with std::is_unsigned instead. - Changed from EXPECT_XXX to ASSERT_XXX in the unittests since a lot of the test contains loops that would otherwise just spam the terminal. BUG= Review URL: https://codereview.webrtc.org/1786043004 Cr-Commit-Position: refs/heads/master@{#11982} --- webrtc/base/mod_ops.h | 39 ++++++++--- webrtc/base/mod_ops_unittest.cc | 114 ++++++++++++++++++++------------ 2 files changed, 100 insertions(+), 53 deletions(-) diff --git a/webrtc/base/mod_ops.h b/webrtc/base/mod_ops.h index 9e649b75d2..cf65fdd4df 100644 --- a/webrtc/base/mod_ops.h +++ b/webrtc/base/mod_ops.h @@ -16,11 +16,6 @@ #include "webrtc/base/checks.h" -#define MOD_OPS_ASSERT_TYPE_IS_UNSIGNED(T) \ - static_assert(std::numeric_limits::is_integer && \ - !std::numeric_limits::is_signed, \ - "Type must be of unsigned integer.") - namespace webrtc { template // NOLINT @@ -42,7 +37,7 @@ inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT return a - sub; } -// Calculates the forward difference between two numbers. +// Calculates the forward difference between two wrapping numbers. // // Example: // uint8_t x = 253; @@ -64,13 +59,23 @@ inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT // ################################################# // -->-----> |----->--- // +template +inline T ForwardDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + RTC_DCHECK_LT(a, M); + RTC_DCHECK_LT(b, M); + return a <= b ? b - a : M - (a - b); +} + template inline T ForwardDiff(T a, T b) { - MOD_OPS_ASSERT_TYPE_IS_UNSIGNED(T); + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); return b - a; } -// Calculates the reverse difference between two numbers. +// Calculates the reverse difference between two wrapping numbers. // // Example: // uint8_t x = 253; @@ -92,9 +97,19 @@ inline T ForwardDiff(T a, T b) { // ################################################# // ---<-----| |<-----<-- // +template +inline T ReverseDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + RTC_DCHECK_LT(a, M); + RTC_DCHECK_LT(b, M); + return b <= a ? a - b : M - (b - a); +} + template inline T ReverseDiff(T a, T b) { - MOD_OPS_ASSERT_TYPE_IS_UNSIGNED(T); + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); return a - b; } @@ -104,7 +119,8 @@ inline T ReverseDiff(T a, T b) { // be ahead. template inline bool AheadOrAt(T a, T b) { - MOD_OPS_ASSERT_TYPE_IS_UNSIGNED(T); + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); const T maxDist = std::numeric_limits::max() / 2 + T(1); if (a - b == maxDist) return b < a; @@ -114,7 +130,8 @@ inline bool AheadOrAt(T a, T b) { // Test if sequence number a is ahead of sequence number b. template inline bool AheadOf(T a, T b) { - MOD_OPS_ASSERT_TYPE_IS_UNSIGNED(T); + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); return a != b && AheadOrAt(a, b); } diff --git a/webrtc/base/mod_ops_unittest.cc b/webrtc/base/mod_ops_unittest.cc index 13e638fb6e..76484bc16b 100644 --- a/webrtc/base/mod_ops_unittest.cc +++ b/webrtc/base/mod_ops_unittest.cc @@ -21,15 +21,15 @@ class TestModOps : public ::testing::Test { TEST_F(TestModOps, Add) { const int D = 100; - EXPECT_EQ(1u, Add(0, 1)); - EXPECT_EQ(0u, Add(0, D)); + ASSERT_EQ(1u, Add(0, 1)); + ASSERT_EQ(0u, Add(0, D)); for (int i = 0; i < D; ++i) - EXPECT_EQ(0u, Add(i, D - i)); + ASSERT_EQ(0u, Add(i, D - i)); int t = 37; uint8_t a = t; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(a, static_cast(t)); + ASSERT_EQ(a, static_cast(t)); t = Add<256>(t, 1); ++a; } @@ -39,22 +39,22 @@ TEST_F(TestModOps, AddLarge) { // NOLINTNEXTLINE const unsigned long D = ulmax - 10ul; // NOLINT unsigned long l = D - 1ul; // NOLINT - EXPECT_EQ(D - 2ul, Add(l, l)); - EXPECT_EQ(9ul, Add(l, ulmax)); - EXPECT_EQ(10ul, Add(0ul, ulmax)); + ASSERT_EQ(D - 2ul, Add(l, l)); + ASSERT_EQ(9ul, Add(l, ulmax)); + ASSERT_EQ(10ul, Add(0ul, ulmax)); } TEST_F(TestModOps, Subtract) { const int D = 100; - EXPECT_EQ(99u, Subtract(0, 1)); - EXPECT_EQ(0u, Subtract(0, D)); + ASSERT_EQ(99u, Subtract(0, 1)); + ASSERT_EQ(0u, Subtract(0, D)); for (int i = 0; i < D; ++i) - EXPECT_EQ(0u, Subtract(i, D + i)); + ASSERT_EQ(0u, Subtract(i, D + i)); int t = 37; uint8_t a = t; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(a, static_cast(t)); + ASSERT_EQ(a, static_cast(t)); t = Subtract<256>(t, 1); --a; } @@ -64,44 +64,44 @@ TEST_F(TestModOps, SubtractLarge) { // NOLINTNEXTLINE const unsigned long D = ulmax - 10ul; // NOLINT unsigned long l = D - 1ul; // NOLINT - EXPECT_EQ(0ul, Subtract(l, l)); - EXPECT_EQ(D - 11ul, Subtract(l, ulmax)); - EXPECT_EQ(D - 10ul, Subtract(0ul, ulmax)); + ASSERT_EQ(0ul, Subtract(l, l)); + ASSERT_EQ(D - 11ul, Subtract(l, ulmax)); + ASSERT_EQ(D - 10ul, Subtract(0ul, ulmax)); } TEST_F(TestModOps, ForwardDiff) { - EXPECT_EQ(0u, ForwardDiff(4711u, 4711u)); + ASSERT_EQ(0u, ForwardDiff(4711u, 4711u)); uint8_t x = 0; uint8_t y = 255; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(255u, ForwardDiff(x, y)); + ASSERT_EQ(255u, ForwardDiff(x, y)); ++x; ++y; } int yi = 255; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(255u, ForwardDiff(x, yi)); + ASSERT_EQ(255u, ForwardDiff(x, yi)); ++x; ++yi; } } TEST_F(TestModOps, ReverseDiff) { - EXPECT_EQ(0u, ReverseDiff(4711u, 4711u)); + ASSERT_EQ(0u, ReverseDiff(4711u, 4711u)); uint8_t x = 0; uint8_t y = 255; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(1u, ReverseDiff(x, y)); + ASSERT_EQ(1u, ReverseDiff(x, y)); ++x; ++y; } int yi = 255; for (int i = 0; i < 256; ++i) { - EXPECT_EQ(1u, ReverseDiff(x, yi)); + ASSERT_EQ(1u, ReverseDiff(x, yi)); ++x; ++yi; } @@ -110,37 +110,37 @@ TEST_F(TestModOps, ReverseDiff) { TEST_F(TestModOps, AheadOrAt) { uint8_t x = 0; uint8_t y = 0; - EXPECT_TRUE(AheadOrAt(x, y)); + ASSERT_TRUE(AheadOrAt(x, y)); ++x; - EXPECT_TRUE(AheadOrAt(x, y)); - EXPECT_FALSE(AheadOrAt(y, x)); + ASSERT_TRUE(AheadOrAt(x, y)); + ASSERT_FALSE(AheadOrAt(y, x)); for (int i = 0; i < 256; ++i) { - EXPECT_TRUE(AheadOrAt(x, y)); + ASSERT_TRUE(AheadOrAt(x, y)); ++x; ++y; } x = 128; y = 0; - EXPECT_TRUE(AheadOrAt(x, y)); - EXPECT_FALSE(AheadOrAt(y, x)); + ASSERT_TRUE(AheadOrAt(x, y)); + ASSERT_FALSE(AheadOrAt(y, x)); x = 129; - EXPECT_FALSE(AheadOrAt(x, y)); - EXPECT_TRUE(AheadOrAt(y, x)); - EXPECT_TRUE(AheadOrAt(x, y)); - EXPECT_FALSE(AheadOrAt(y, x)); + ASSERT_FALSE(AheadOrAt(x, y)); + ASSERT_TRUE(AheadOrAt(y, x)); + ASSERT_TRUE(AheadOrAt(x, y)); + ASSERT_FALSE(AheadOrAt(y, x)); } TEST_F(TestModOps, AheadOf) { uint8_t x = 0; uint8_t y = 0; - EXPECT_FALSE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(x, y)); ++x; - EXPECT_TRUE(AheadOf(x, y)); - EXPECT_FALSE(AheadOf(y, x)); + ASSERT_TRUE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(y, x)); for (int i = 0; i < 256; ++i) { - EXPECT_TRUE(AheadOf(x, y)); + ASSERT_TRUE(AheadOf(x, y)); ++x; ++y; } @@ -148,25 +148,55 @@ TEST_F(TestModOps, AheadOf) { x = 128; y = 0; for (int i = 0; i < 128; ++i) { - EXPECT_TRUE(AheadOf(x, y)); - EXPECT_FALSE(AheadOf(y, x)); + ASSERT_TRUE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(y, x)); x++; y++; } for (int i = 0; i < 128; ++i) { - EXPECT_FALSE(AheadOf(x, y)); - EXPECT_TRUE(AheadOf(y, x)); + ASSERT_FALSE(AheadOf(x, y)); + ASSERT_TRUE(AheadOf(y, x)); x++; y++; } x = 129; y = 0; - EXPECT_FALSE(AheadOf(x, y)); - EXPECT_TRUE(AheadOf(y, x)); - EXPECT_TRUE(AheadOf(x, y)); - EXPECT_FALSE(AheadOf(y, x)); + ASSERT_FALSE(AheadOf(x, y)); + ASSERT_TRUE(AheadOf(y, x)); + ASSERT_TRUE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(y, x)); +} + +TEST_F(TestModOps, ForwardDiffWithDivisor) { + const uint8_t kDivisor = 211; + + for (uint8_t i = 0; i < kDivisor - 1; ++i) { + ASSERT_EQ(0, (ForwardDiff(i, i))); + ASSERT_EQ(1, (ForwardDiff(i, i + 1))); + ASSERT_EQ(kDivisor - 1, (ForwardDiff(i + 1, i))); + } + + for (uint8_t i = 1; i < kDivisor; ++i) { + ASSERT_EQ(i, (ForwardDiff(0, i))); + ASSERT_EQ(kDivisor - i, (ForwardDiff(i, 0))); + } +} + +TEST_F(TestModOps, ReverseDiffWithDivisor) { + const uint8_t kDivisor = 241; + + for (uint8_t i = 0; i < kDivisor - 1; ++i) { + ASSERT_EQ(0, (ReverseDiff(i, i))); + ASSERT_EQ(kDivisor - 1, (ReverseDiff(i, i + 1))); + ASSERT_EQ(1, (ReverseDiff(i + 1, i))); + } + + for (uint8_t i = 1; i < kDivisor; ++i) { + ASSERT_EQ(kDivisor - i, (ReverseDiff(0, i))); + ASSERT_EQ(i, (ReverseDiff(i, 0))); + } } } // namespace webrtc