From 8a44e1d87b2f80db21eda24d0c0c5742c2060827 Mon Sep 17 00:00:00 2001 From: kwiberg Date: Tue, 1 Nov 2016 12:04:26 -0700 Subject: [PATCH] Let RTC_[D]CHECK_op accept arguments of different signedness With this change, instead of RTC_DCHECK_GE(unsigned_var, 17u); we can simply write RTC_DCHECK_GE(unsigned_var, 17); or even RTC_DCHECK_GE(unsigned_var, -17); // Always true. and the mathematically sensible thing will happen. Perhaps more importantly, we can replace checks like // index is size_t, num_channels is int. RTC_DCHECK(num_channels >= 0 && index < static_cast(num_channels)); or, even worse, just // Surely num_channels isn't negative. That would be absurd! RTC_DCHECK_LT(index, static_cast(num_channels)); with simply RTC_DCHECK_LT(index, num_channels); In short, you no longer have to keep track of the signedness of the arguments, because the sensible thing will happen. BUG=webrtc:6645 Review-Url: https://codereview.webrtc.org/2459793002 Cr-Commit-Position: refs/heads/master@{#14878} --- webrtc/BUILD.gn | 1 + webrtc/base/BUILD.gn | 1 + webrtc/base/checks.h | 50 +-- webrtc/base/safe_compare.h | 180 +++++++++ webrtc/base/safe_compare_unittest.cc | 379 ++++++++++++++++++ .../audio_coding/neteq/dtmf_tone_generator.cc | 4 +- 6 files changed, 588 insertions(+), 27 deletions(-) create mode 100644 webrtc/base/safe_compare.h create mode 100644 webrtc/base/safe_compare_unittest.cc diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn index 9e420baa42..0dd61bbb86 100644 --- a/webrtc/BUILD.gn +++ b/webrtc/BUILD.gn @@ -437,6 +437,7 @@ if (rtc_include_tests) { "base/rollingaccumulator_unittest.cc", "base/rtccertificate_unittest.cc", "base/rtccertificategenerator_unittest.cc", + "base/safe_compare_unittest.cc", "base/scopedptrcollection_unittest.cc", "base/sequenced_task_checker_unittest.cc", "base/sha1digest_unittest.cc", diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index aed11586b5..2c25050a86 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn @@ -159,6 +159,7 @@ rtc_static_library("rtc_base_approved") { "ratetracker.h", "refcount.h", "refcountedobject.h", + "safe_compare.h", "safe_conversions.h", "safe_conversions_impl.h", "sanitizer.h", diff --git a/webrtc/base/checks.h b/webrtc/base/checks.h index aa6725dec7..653ed322e7 100644 --- a/webrtc/base/checks.h +++ b/webrtc/base/checks.h @@ -36,6 +36,8 @@ NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg); #include #include +#include "webrtc/base/safe_compare.h" + // The macros here print a message to stderr and abort under various // conditions. All will accept additional stream messages. For example: // RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar."; @@ -96,10 +98,8 @@ namespace rtc { // Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if // values of the same types as |a| and |b| can't be compared with the given // operation, and that would evaluate |a| and |b| if evaluated. -#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \ - RTC_EAT_STREAM_PARAMETERS(((void)sizeof(std::declval() \ - op std::declval()), \ - (void)(a), (void)(b))) +#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \ + RTC_EAT_STREAM_PARAMETERS(((void)rtc::safe_cmp::op(a, b))) // RTC_CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG or anything else, so the check will be executed @@ -158,35 +158,35 @@ std::string* MakeCheckOpString( // The (int, int) specialization works around the issue that the compiler // will not instantiate the template version of the function on values of // unnamed enum type - see comment below. -#define DEFINE_RTC_CHECK_OP_IMPL(name, op) \ +#define DEFINE_RTC_CHECK_OP_IMPL(name) \ template \ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ const char* names) { \ - if (v1 op v2) \ + if (rtc::safe_cmp::name(v1, v2)) \ return NULL; \ else \ return rtc::MakeCheckOpString(v1, v2, names); \ } \ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ - if (v1 op v2) \ + if (rtc::safe_cmp::name(v1, v2)) \ return NULL; \ else \ return rtc::MakeCheckOpString(v1, v2, names); \ } -DEFINE_RTC_CHECK_OP_IMPL(EQ, ==) -DEFINE_RTC_CHECK_OP_IMPL(NE, !=) -DEFINE_RTC_CHECK_OP_IMPL(LE, <=) -DEFINE_RTC_CHECK_OP_IMPL(LT, < ) -DEFINE_RTC_CHECK_OP_IMPL(GE, >=) -DEFINE_RTC_CHECK_OP_IMPL(GT, > ) +DEFINE_RTC_CHECK_OP_IMPL(Eq) +DEFINE_RTC_CHECK_OP_IMPL(Ne) +DEFINE_RTC_CHECK_OP_IMPL(Le) +DEFINE_RTC_CHECK_OP_IMPL(Lt) +DEFINE_RTC_CHECK_OP_IMPL(Ge) +DEFINE_RTC_CHECK_OP_IMPL(Gt) #undef DEFINE_RTC_CHECK_OP_IMPL -#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(EQ, ==, val1, val2) -#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(NE, !=, val1, val2) -#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(LE, <=, val1, val2) -#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(LT, < , val1, val2) -#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(GE, >=, val1, val2) -#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(GT, > , val1, val2) +#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2) +#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2) +#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2) +#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2) +#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2) +#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2) // The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates // code in debug builds. It does reference the condition parameter in all cases, @@ -201,12 +201,12 @@ DEFINE_RTC_CHECK_OP_IMPL(GT, > ) #define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2) #else #define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition) -#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(==, v1, v2) -#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(!=, v1, v2) -#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(<=, v1, v2) -#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(<, v1, v2) -#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(>=, v1, v2) -#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(>, v1, v2) +#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2) +#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2) +#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2) +#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2) +#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2) +#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2) #endif // This is identical to LogMessageVoidify but in name. diff --git a/webrtc/base/safe_compare.h b/webrtc/base/safe_compare.h new file mode 100644 index 0000000000..37ddf780c7 --- /dev/null +++ b/webrtc/base/safe_compare.h @@ -0,0 +1,180 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file defines six functions: +// +// rtc::safe_cmp::Eq // == +// rtc::safe_cmp::Ne // != +// rtc::safe_cmp::Lt // < +// rtc::safe_cmp::Le // <= +// rtc::safe_cmp::Gt // > +// rtc::safe_cmp::Ge // >= +// +// They each accept two arguments of arbitrary types, and in almost all cases, +// they simply call the appropriate comparison operator. However, if both +// arguments are integers, they don't compare them using C++'s quirky rules, +// but instead adhere to the true mathematical definitions. It is as if the +// arguments were first converted to infinite-range signed integers, and then +// compared, although of course nothing expensive like that actually takes +// place. In practice, for signed/signed and unsigned/unsigned comparisons and +// some mixed-signed comparisons with a compile-time constant, the overhead is +// zero; in the remaining cases, it is just a few machine instructions (no +// branches). + +#ifndef WEBRTC_BASE_SAFE_COMPARE_H_ +#define WEBRTC_BASE_SAFE_COMPARE_H_ + +#include +#include + +#include +#include + +namespace rtc { +namespace safe_cmp { + +namespace safe_cmp_impl { + +template +struct LargerIntImpl : std::false_type {}; +template <> +struct LargerIntImpl : std::true_type { + using type = int16_t; +}; +template <> +struct LargerIntImpl : std::true_type { + using type = int32_t; +}; +template <> +struct LargerIntImpl : std::true_type { + using type = int64_t; +}; + +// LargerInt::value is true iff there's a signed type that's larger +// than T1 (and no larger than the larger of T2 and int*, for performance +// reasons); and if there is such a type, LargerInt::type is an alias +// for it. +template +struct LargerInt + : LargerIntImpl {}; + +template +inline typename std::make_unsigned::type MakeUnsigned(T a) { + return static_cast::type>(a); +} + +// Overload for when both T1 and T2 have the same signedness. +template ::value == + std::is_signed::value>::type* = nullptr> +inline bool Cmp(T1 a, T2 b) { + return Op::Op(a, b); +} + +// Overload for signed - unsigned comparison that can be promoted to a bigger +// signed type. +template ::value && + std::is_unsigned::value && + LargerInt::value>::type* = nullptr> +inline bool Cmp(T1 a, T2 b) { + return Op::Op(a, static_cast::type>(b)); +} + +// Overload for unsigned - signed comparison that can be promoted to a bigger +// signed type. +template ::value && + std::is_signed::value && + LargerInt::value>::type* = nullptr> +inline bool Cmp(T1 a, T2 b) { + return Op::Op(static_cast::type>(a), b); +} + +// Overload for signed - unsigned comparison that can't be promoted to a bigger +// signed type. +template ::value && + std::is_unsigned::value && + !LargerInt::value>::type* = nullptr> +inline bool Cmp(T1 a, T2 b) { + return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); +} + +// Overload for unsigned - signed comparison that can't be promoted to a bigger +// signed type. +template ::value && + std::is_signed::value && + !LargerInt::value>::type* = nullptr> +inline bool Cmp(T1 a, T2 b) { + return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); +} + +#define RTC_SAFECMP_MAKE_OP(name, op) \ + struct name { \ + template \ + static constexpr bool Op(T1 a, T2 b) { \ + return a op b; \ + } \ + }; +RTC_SAFECMP_MAKE_OP(EqOp, ==) +RTC_SAFECMP_MAKE_OP(NeOp, !=) +RTC_SAFECMP_MAKE_OP(LtOp, <) +RTC_SAFECMP_MAKE_OP(LeOp, <=) +RTC_SAFECMP_MAKE_OP(GtOp, >) +RTC_SAFECMP_MAKE_OP(GeOp, >=) +#undef RTC_SAFECMP_MAKE_OP + +} // namespace safe_cmp_impl + +#define RTC_SAFECMP_MAKE_FUN(name) \ + template < \ + typename T1, typename T2, \ + typename std::enable_if< \ + std::is_integral::type>::value && \ + std::is_integral::type>::value>:: \ + type* = nullptr> \ + inline bool name(T1 a, T2 b) { \ + return safe_cmp_impl::Cmp(a, b); \ + } \ + template ::type>::value || \ + !std::is_integral::type>:: \ + value>::type* = nullptr> \ + inline bool name(T1&& a, T2&& b) { \ + return safe_cmp_impl::name##Op::Op(a, b); \ + } +RTC_SAFECMP_MAKE_FUN(Eq) +RTC_SAFECMP_MAKE_FUN(Ne) +RTC_SAFECMP_MAKE_FUN(Lt) +RTC_SAFECMP_MAKE_FUN(Le) +RTC_SAFECMP_MAKE_FUN(Gt) +RTC_SAFECMP_MAKE_FUN(Ge) +#undef RTC_SAFECMP_MAKE_FUN + +} // namespace safe_cmp +} // namespace rtc + +#endif // WEBRTC_BASE_SAFE_COMPARE_H_ diff --git a/webrtc/base/safe_compare_unittest.cc b/webrtc/base/safe_compare_unittest.cc new file mode 100644 index 0000000000..12ab4696ef --- /dev/null +++ b/webrtc/base/safe_compare_unittest.cc @@ -0,0 +1,379 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "webrtc/base/safe_compare.h" +#include "webrtc/test/gtest.h" + +namespace rtc { + +namespace { + +constexpr std::uintmax_t umax = std::numeric_limits::max(); +constexpr std::intmax_t imin = std::numeric_limits::min(); +constexpr std::intmax_t m1 = -1; + +// m1 and umax have the same representation because we use 2's complement +// arithmetic, so naive casting will confuse them. +static_assert(static_cast(m1) == umax, ""); +static_assert(m1 == static_cast(umax), ""); + +std::pair p1(1, 1); +std::pair p2(1, 2); + +} // namespace + +// clang-format off + +// These functions aren't used in the tests, but it's useful to look at the +// compiler output for them, and verify that (1) the same-signedness *Safe +// functions result in exactly the same code as their *Ref counterparts, and +// that (2) the mixed-signedness *Safe functions have just a few extra +// arithmetic and logic instructions (but no extra control flow instructions). +bool TestLessThanRef( int a, int b) { return a < b; } +bool TestLessThanRef( unsigned a, unsigned b) { return a < b; } +bool TestLessThanSafe( int a, int b) { return safe_cmp::Lt(a, b); } +bool TestLessThanSafe(unsigned a, unsigned b) { return safe_cmp::Lt(a, b); } +bool TestLessThanSafe(unsigned a, int b) { return safe_cmp::Lt(a, b); } +bool TestLessThanSafe( int a, unsigned b) { return safe_cmp::Lt(a, b); } + +// For these, we expect the *Ref and *Safe functions to result in identical +// code, except for the ones that compare a signed variable with an unsigned +// constant; in that case, the *Ref function does an unsigned comparison (fast +// but incorrect) and the *Safe function spends a few extra instructions on +// doing it right. +bool TestLessThan17Ref( int a) { return a < 17; } +bool TestLessThan17Ref( unsigned a) { return a < 17; } +bool TestLessThan17uRef( int a) { return static_cast(a) < 17u; } +bool TestLessThan17uRef( unsigned a) { return a < 17u; } +bool TestLessThan17Safe( int a) { return safe_cmp::Lt(a, 17); } +bool TestLessThan17Safe( unsigned a) { return safe_cmp::Lt(a, 17); } +bool TestLessThan17uSafe( int a) { return safe_cmp::Lt(a, 17u); } +bool TestLessThan17uSafe(unsigned a) { return safe_cmp::Lt(a, 17u); } + +// Cases where we can't convert to a larger signed type. +bool TestLessThanMax( intmax_t a, uintmax_t b) { return safe_cmp::Lt(a, b); } +bool TestLessThanMax(uintmax_t a, intmax_t b) { return safe_cmp::Lt(a, b); } +bool TestLessThanMax17u( intmax_t a) { return safe_cmp::Lt(a, uintmax_t{17}); } +bool TestLessThanMax17( uintmax_t a) { return safe_cmp::Lt(a, intmax_t{17}); } + +// Cases where the compiler should be able to compute the result at compile +// time. +bool TestLessThanConst1() { return safe_cmp::Lt( -1, 1); } +bool TestLessThanConst2() { return safe_cmp::Lt( m1, umax); } +bool TestLessThanConst3() { return safe_cmp::Lt(umax, imin); } +bool TestLessThanConst4(unsigned a) { return safe_cmp::Lt( a, -1); } +bool TestLessThanConst5(unsigned a) { return safe_cmp::Lt(-1, a); } +bool TestLessThanConst6(unsigned a) { return safe_cmp::Lt( a, a); } + +// clang-format on + +TEST(SafeCmpTest, Eq) { + EXPECT_FALSE(safe_cmp::Eq(-1, 2)); + EXPECT_FALSE(safe_cmp::Eq(-1, 2u)); + EXPECT_FALSE(safe_cmp::Eq(2, -1)); + EXPECT_FALSE(safe_cmp::Eq(2u, -1)); + + EXPECT_FALSE(safe_cmp::Eq(1, 2)); + EXPECT_FALSE(safe_cmp::Eq(1, 2u)); + EXPECT_FALSE(safe_cmp::Eq(1u, 2)); + EXPECT_FALSE(safe_cmp::Eq(1u, 2u)); + EXPECT_FALSE(safe_cmp::Eq(2, 1)); + EXPECT_FALSE(safe_cmp::Eq(2, 1u)); + EXPECT_FALSE(safe_cmp::Eq(2u, 1)); + EXPECT_FALSE(safe_cmp::Eq(2u, 1u)); + + EXPECT_TRUE(safe_cmp::Eq(2, 2)); + EXPECT_TRUE(safe_cmp::Eq(2, 2u)); + EXPECT_TRUE(safe_cmp::Eq(2u, 2)); + EXPECT_TRUE(safe_cmp::Eq(2u, 2u)); + + EXPECT_TRUE(safe_cmp::Eq(imin, imin)); + EXPECT_FALSE(safe_cmp::Eq(imin, umax)); + EXPECT_FALSE(safe_cmp::Eq(umax, imin)); + EXPECT_TRUE(safe_cmp::Eq(umax, umax)); + + EXPECT_TRUE(safe_cmp::Eq(m1, m1)); + EXPECT_FALSE(safe_cmp::Eq(m1, umax)); + EXPECT_FALSE(safe_cmp::Eq(umax, m1)); + EXPECT_TRUE(safe_cmp::Eq(umax, umax)); + + EXPECT_FALSE(safe_cmp::Eq(1, 2)); + EXPECT_FALSE(safe_cmp::Eq(1, 2.0)); + EXPECT_FALSE(safe_cmp::Eq(1.0, 2)); + EXPECT_FALSE(safe_cmp::Eq(1.0, 2.0)); + EXPECT_FALSE(safe_cmp::Eq(2, 1)); + EXPECT_FALSE(safe_cmp::Eq(2, 1.0)); + EXPECT_FALSE(safe_cmp::Eq(2.0, 1)); + EXPECT_FALSE(safe_cmp::Eq(2.0, 1.0)); + + EXPECT_TRUE(safe_cmp::Eq(2, 2)); + EXPECT_TRUE(safe_cmp::Eq(2, 2.0)); + EXPECT_TRUE(safe_cmp::Eq(2.0, 2)); + EXPECT_TRUE(safe_cmp::Eq(2.0, 2.0)); + + EXPECT_TRUE(safe_cmp::Eq(p1, p1)); + EXPECT_FALSE(safe_cmp::Eq(p1, p2)); + EXPECT_FALSE(safe_cmp::Eq(p2, p1)); + EXPECT_TRUE(safe_cmp::Eq(p2, p2)); +} + +TEST(SafeCmpTest, Ne) { + EXPECT_TRUE(safe_cmp::Ne(-1, 2)); + EXPECT_TRUE(safe_cmp::Ne(-1, 2u)); + EXPECT_TRUE(safe_cmp::Ne(2, -1)); + EXPECT_TRUE(safe_cmp::Ne(2u, -1)); + + EXPECT_TRUE(safe_cmp::Ne(1, 2)); + EXPECT_TRUE(safe_cmp::Ne(1, 2u)); + EXPECT_TRUE(safe_cmp::Ne(1u, 2)); + EXPECT_TRUE(safe_cmp::Ne(1u, 2u)); + EXPECT_TRUE(safe_cmp::Ne(2, 1)); + EXPECT_TRUE(safe_cmp::Ne(2, 1u)); + EXPECT_TRUE(safe_cmp::Ne(2u, 1)); + EXPECT_TRUE(safe_cmp::Ne(2u, 1u)); + + EXPECT_FALSE(safe_cmp::Ne(2, 2)); + EXPECT_FALSE(safe_cmp::Ne(2, 2u)); + EXPECT_FALSE(safe_cmp::Ne(2u, 2)); + EXPECT_FALSE(safe_cmp::Ne(2u, 2u)); + + EXPECT_FALSE(safe_cmp::Ne(imin, imin)); + EXPECT_TRUE(safe_cmp::Ne(imin, umax)); + EXPECT_TRUE(safe_cmp::Ne(umax, imin)); + EXPECT_FALSE(safe_cmp::Ne(umax, umax)); + + EXPECT_FALSE(safe_cmp::Ne(m1, m1)); + EXPECT_TRUE(safe_cmp::Ne(m1, umax)); + EXPECT_TRUE(safe_cmp::Ne(umax, m1)); + EXPECT_FALSE(safe_cmp::Ne(umax, umax)); + + EXPECT_TRUE(safe_cmp::Ne(1, 2)); + EXPECT_TRUE(safe_cmp::Ne(1, 2.0)); + EXPECT_TRUE(safe_cmp::Ne(1.0, 2)); + EXPECT_TRUE(safe_cmp::Ne(1.0, 2.0)); + EXPECT_TRUE(safe_cmp::Ne(2, 1)); + EXPECT_TRUE(safe_cmp::Ne(2, 1.0)); + EXPECT_TRUE(safe_cmp::Ne(2.0, 1)); + EXPECT_TRUE(safe_cmp::Ne(2.0, 1.0)); + + EXPECT_FALSE(safe_cmp::Ne(2, 2)); + EXPECT_FALSE(safe_cmp::Ne(2, 2.0)); + EXPECT_FALSE(safe_cmp::Ne(2.0, 2)); + EXPECT_FALSE(safe_cmp::Ne(2.0, 2.0)); + + EXPECT_FALSE(safe_cmp::Ne(p1, p1)); + EXPECT_TRUE(safe_cmp::Ne(p1, p2)); + EXPECT_TRUE(safe_cmp::Ne(p2, p1)); + EXPECT_FALSE(safe_cmp::Ne(p2, p2)); +} + +TEST(SafeCmpTest, Lt) { + EXPECT_TRUE(safe_cmp::Lt(-1, 2)); + EXPECT_TRUE(safe_cmp::Lt(-1, 2u)); + EXPECT_FALSE(safe_cmp::Lt(2, -1)); + EXPECT_FALSE(safe_cmp::Lt(2u, -1)); + + EXPECT_TRUE(safe_cmp::Lt(1, 2)); + EXPECT_TRUE(safe_cmp::Lt(1, 2u)); + EXPECT_TRUE(safe_cmp::Lt(1u, 2)); + EXPECT_TRUE(safe_cmp::Lt(1u, 2u)); + EXPECT_FALSE(safe_cmp::Lt(2, 1)); + EXPECT_FALSE(safe_cmp::Lt(2, 1u)); + EXPECT_FALSE(safe_cmp::Lt(2u, 1)); + EXPECT_FALSE(safe_cmp::Lt(2u, 1u)); + + EXPECT_FALSE(safe_cmp::Lt(2, 2)); + EXPECT_FALSE(safe_cmp::Lt(2, 2u)); + EXPECT_FALSE(safe_cmp::Lt(2u, 2)); + EXPECT_FALSE(safe_cmp::Lt(2u, 2u)); + + EXPECT_FALSE(safe_cmp::Lt(imin, imin)); + EXPECT_TRUE(safe_cmp::Lt(imin, umax)); + EXPECT_FALSE(safe_cmp::Lt(umax, imin)); + EXPECT_FALSE(safe_cmp::Lt(umax, umax)); + + EXPECT_FALSE(safe_cmp::Lt(m1, m1)); + EXPECT_TRUE(safe_cmp::Lt(m1, umax)); + EXPECT_FALSE(safe_cmp::Lt(umax, m1)); + EXPECT_FALSE(safe_cmp::Lt(umax, umax)); + + EXPECT_TRUE(safe_cmp::Lt(1, 2)); + EXPECT_TRUE(safe_cmp::Lt(1, 2.0)); + EXPECT_TRUE(safe_cmp::Lt(1.0, 2)); + EXPECT_TRUE(safe_cmp::Lt(1.0, 2.0)); + EXPECT_FALSE(safe_cmp::Lt(2, 1)); + EXPECT_FALSE(safe_cmp::Lt(2, 1.0)); + EXPECT_FALSE(safe_cmp::Lt(2.0, 1)); + EXPECT_FALSE(safe_cmp::Lt(2.0, 1.0)); + + EXPECT_FALSE(safe_cmp::Lt(2, 2)); + EXPECT_FALSE(safe_cmp::Lt(2, 2.0)); + EXPECT_FALSE(safe_cmp::Lt(2.0, 2)); + EXPECT_FALSE(safe_cmp::Lt(2.0, 2.0)); + + EXPECT_FALSE(safe_cmp::Lt(p1, p1)); + EXPECT_TRUE(safe_cmp::Lt(p1, p2)); + EXPECT_FALSE(safe_cmp::Lt(p2, p1)); + EXPECT_FALSE(safe_cmp::Lt(p2, p2)); +} + +TEST(SafeCmpTest, Le) { + EXPECT_TRUE(safe_cmp::Le(-1, 2)); + EXPECT_TRUE(safe_cmp::Le(-1, 2u)); + EXPECT_FALSE(safe_cmp::Le(2, -1)); + EXPECT_FALSE(safe_cmp::Le(2u, -1)); + + EXPECT_TRUE(safe_cmp::Le(1, 2)); + EXPECT_TRUE(safe_cmp::Le(1, 2u)); + EXPECT_TRUE(safe_cmp::Le(1u, 2)); + EXPECT_TRUE(safe_cmp::Le(1u, 2u)); + EXPECT_FALSE(safe_cmp::Le(2, 1)); + EXPECT_FALSE(safe_cmp::Le(2, 1u)); + EXPECT_FALSE(safe_cmp::Le(2u, 1)); + EXPECT_FALSE(safe_cmp::Le(2u, 1u)); + + EXPECT_TRUE(safe_cmp::Le(2, 2)); + EXPECT_TRUE(safe_cmp::Le(2, 2u)); + EXPECT_TRUE(safe_cmp::Le(2u, 2)); + EXPECT_TRUE(safe_cmp::Le(2u, 2u)); + + EXPECT_TRUE(safe_cmp::Le(imin, imin)); + EXPECT_TRUE(safe_cmp::Le(imin, umax)); + EXPECT_FALSE(safe_cmp::Le(umax, imin)); + EXPECT_TRUE(safe_cmp::Le(umax, umax)); + + EXPECT_TRUE(safe_cmp::Le(m1, m1)); + EXPECT_TRUE(safe_cmp::Le(m1, umax)); + EXPECT_FALSE(safe_cmp::Le(umax, m1)); + EXPECT_TRUE(safe_cmp::Le(umax, umax)); + + EXPECT_TRUE(safe_cmp::Le(1, 2)); + EXPECT_TRUE(safe_cmp::Le(1, 2.0)); + EXPECT_TRUE(safe_cmp::Le(1.0, 2)); + EXPECT_TRUE(safe_cmp::Le(1.0, 2.0)); + EXPECT_FALSE(safe_cmp::Le(2, 1)); + EXPECT_FALSE(safe_cmp::Le(2, 1.0)); + EXPECT_FALSE(safe_cmp::Le(2.0, 1)); + EXPECT_FALSE(safe_cmp::Le(2.0, 1.0)); + + EXPECT_TRUE(safe_cmp::Le(2, 2)); + EXPECT_TRUE(safe_cmp::Le(2, 2.0)); + EXPECT_TRUE(safe_cmp::Le(2.0, 2)); + EXPECT_TRUE(safe_cmp::Le(2.0, 2.0)); + + EXPECT_TRUE(safe_cmp::Le(p1, p1)); + EXPECT_TRUE(safe_cmp::Le(p1, p2)); + EXPECT_FALSE(safe_cmp::Le(p2, p1)); + EXPECT_TRUE(safe_cmp::Le(p2, p2)); +} + +TEST(SafeCmpTest, Gt) { + EXPECT_FALSE(safe_cmp::Gt(-1, 2)); + EXPECT_FALSE(safe_cmp::Gt(-1, 2u)); + EXPECT_TRUE(safe_cmp::Gt(2, -1)); + EXPECT_TRUE(safe_cmp::Gt(2u, -1)); + + EXPECT_FALSE(safe_cmp::Gt(1, 2)); + EXPECT_FALSE(safe_cmp::Gt(1, 2u)); + EXPECT_FALSE(safe_cmp::Gt(1u, 2)); + EXPECT_FALSE(safe_cmp::Gt(1u, 2u)); + EXPECT_TRUE(safe_cmp::Gt(2, 1)); + EXPECT_TRUE(safe_cmp::Gt(2, 1u)); + EXPECT_TRUE(safe_cmp::Gt(2u, 1)); + EXPECT_TRUE(safe_cmp::Gt(2u, 1u)); + + EXPECT_FALSE(safe_cmp::Gt(2, 2)); + EXPECT_FALSE(safe_cmp::Gt(2, 2u)); + EXPECT_FALSE(safe_cmp::Gt(2u, 2)); + EXPECT_FALSE(safe_cmp::Gt(2u, 2u)); + + EXPECT_FALSE(safe_cmp::Gt(imin, imin)); + EXPECT_FALSE(safe_cmp::Gt(imin, umax)); + EXPECT_TRUE(safe_cmp::Gt(umax, imin)); + EXPECT_FALSE(safe_cmp::Gt(umax, umax)); + + EXPECT_FALSE(safe_cmp::Gt(m1, m1)); + EXPECT_FALSE(safe_cmp::Gt(m1, umax)); + EXPECT_TRUE(safe_cmp::Gt(umax, m1)); + EXPECT_FALSE(safe_cmp::Gt(umax, umax)); + + EXPECT_FALSE(safe_cmp::Gt(1, 2)); + EXPECT_FALSE(safe_cmp::Gt(1, 2.0)); + EXPECT_FALSE(safe_cmp::Gt(1.0, 2)); + EXPECT_FALSE(safe_cmp::Gt(1.0, 2.0)); + EXPECT_TRUE(safe_cmp::Gt(2, 1)); + EXPECT_TRUE(safe_cmp::Gt(2, 1.0)); + EXPECT_TRUE(safe_cmp::Gt(2.0, 1)); + EXPECT_TRUE(safe_cmp::Gt(2.0, 1.0)); + + EXPECT_FALSE(safe_cmp::Gt(2, 2)); + EXPECT_FALSE(safe_cmp::Gt(2, 2.0)); + EXPECT_FALSE(safe_cmp::Gt(2.0, 2)); + EXPECT_FALSE(safe_cmp::Gt(2.0, 2.0)); + + EXPECT_FALSE(safe_cmp::Gt(p1, p1)); + EXPECT_FALSE(safe_cmp::Gt(p1, p2)); + EXPECT_TRUE(safe_cmp::Gt(p2, p1)); + EXPECT_FALSE(safe_cmp::Gt(p2, p2)); +} + +TEST(SafeCmpTest, Ge) { + EXPECT_FALSE(safe_cmp::Ge(-1, 2)); + EXPECT_FALSE(safe_cmp::Ge(-1, 2u)); + EXPECT_TRUE(safe_cmp::Ge(2, -1)); + EXPECT_TRUE(safe_cmp::Ge(2u, -1)); + + EXPECT_FALSE(safe_cmp::Ge(1, 2)); + EXPECT_FALSE(safe_cmp::Ge(1, 2u)); + EXPECT_FALSE(safe_cmp::Ge(1u, 2)); + EXPECT_FALSE(safe_cmp::Ge(1u, 2u)); + EXPECT_TRUE(safe_cmp::Ge(2, 1)); + EXPECT_TRUE(safe_cmp::Ge(2, 1u)); + EXPECT_TRUE(safe_cmp::Ge(2u, 1)); + EXPECT_TRUE(safe_cmp::Ge(2u, 1u)); + + EXPECT_TRUE(safe_cmp::Ge(2, 2)); + EXPECT_TRUE(safe_cmp::Ge(2, 2u)); + EXPECT_TRUE(safe_cmp::Ge(2u, 2)); + EXPECT_TRUE(safe_cmp::Ge(2u, 2u)); + + EXPECT_TRUE(safe_cmp::Ge(imin, imin)); + EXPECT_FALSE(safe_cmp::Ge(imin, umax)); + EXPECT_TRUE(safe_cmp::Ge(umax, imin)); + EXPECT_TRUE(safe_cmp::Ge(umax, umax)); + + EXPECT_TRUE(safe_cmp::Ge(m1, m1)); + EXPECT_FALSE(safe_cmp::Ge(m1, umax)); + EXPECT_TRUE(safe_cmp::Ge(umax, m1)); + EXPECT_TRUE(safe_cmp::Ge(umax, umax)); + + EXPECT_FALSE(safe_cmp::Ge(1, 2)); + EXPECT_FALSE(safe_cmp::Ge(1, 2.0)); + EXPECT_FALSE(safe_cmp::Ge(1.0, 2)); + EXPECT_FALSE(safe_cmp::Ge(1.0, 2.0)); + EXPECT_TRUE(safe_cmp::Ge(2, 1)); + EXPECT_TRUE(safe_cmp::Ge(2, 1.0)); + EXPECT_TRUE(safe_cmp::Ge(2.0, 1)); + EXPECT_TRUE(safe_cmp::Ge(2.0, 1.0)); + + EXPECT_TRUE(safe_cmp::Ge(2, 2)); + EXPECT_TRUE(safe_cmp::Ge(2, 2.0)); + EXPECT_TRUE(safe_cmp::Ge(2.0, 2)); + EXPECT_TRUE(safe_cmp::Ge(2.0, 2.0)); + + EXPECT_TRUE(safe_cmp::Ge(p1, p1)); + EXPECT_FALSE(safe_cmp::Ge(p1, p2)); + EXPECT_TRUE(safe_cmp::Ge(p2, p1)); + EXPECT_TRUE(safe_cmp::Ge(p2, p2)); +} + +} // namespace rtc diff --git a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc index 9dad2e5efd..947bf6dbaa 100644 --- a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc +++ b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc @@ -134,7 +134,7 @@ int DtmfToneGenerator::Init(int fs, int event, int attenuation) { } // Look up oscillator coefficient for low and high frequencies. - RTC_DCHECK_LE(0u, fs_index); + RTC_DCHECK_LE(0, fs_index); RTC_DCHECK_GT(arraysize(kCoeff1), fs_index); RTC_DCHECK_GT(arraysize(kCoeff2), fs_index); RTC_DCHECK_LE(0, event); @@ -149,7 +149,7 @@ int DtmfToneGenerator::Init(int fs, int event, int attenuation) { amplitude_ = kAmplitude[attenuation]; // Initialize sample history. - RTC_DCHECK_LE(0u, fs_index); + RTC_DCHECK_LE(0, fs_index); RTC_DCHECK_GT(arraysize(kInitValue1), fs_index); RTC_DCHECK_GT(arraysize(kInitValue2), fs_index); RTC_DCHECK_LE(0, event);