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<size_t>(num_channels));

or, even worse, just

  // Surely num_channels isn't negative. That would be absurd!
  RTC_DCHECK_LT(index, static_cast<size_t>(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}
This commit is contained in:
kwiberg
2016-11-01 12:04:26 -07:00
committed by Commit bot
parent 803d97f159
commit 8a44e1d87b
6 changed files with 588 additions and 27 deletions

View File

@ -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",

View File

@ -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",

View File

@ -36,6 +36,8 @@ NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
#include <sstream>
#include <string>
#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.";
@ -97,9 +99,7 @@ namespace rtc {
// 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<decltype(a)>() \
op std::declval<decltype(b)>()), \
(void)(a), (void)(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<std::string, std::string>(
// 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 <class t1, class t2> \
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.

180
webrtc/base/safe_compare.h Normal file
View File

@ -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 <stddef.h>
#include <stdint.h>
#include <type_traits>
#include <utility>
namespace rtc {
namespace safe_cmp {
namespace safe_cmp_impl {
template <size_t N>
struct LargerIntImpl : std::false_type {};
template <>
struct LargerIntImpl<sizeof(int8_t)> : std::true_type {
using type = int16_t;
};
template <>
struct LargerIntImpl<sizeof(int16_t)> : std::true_type {
using type = int32_t;
};
template <>
struct LargerIntImpl<sizeof(int32_t)> : std::true_type {
using type = int64_t;
};
// LargerInt<T1, T2>::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<T1, T2>::type is an alias
// for it.
template <typename T1, typename T2>
struct LargerInt
: LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*)
? sizeof(T1)
: 0> {};
template <typename T>
inline typename std::make_unsigned<T>::type MakeUnsigned(T a) {
return static_cast<typename std::make_unsigned<T>::type>(a);
}
// Overload for when both T1 and T2 have the same signedness.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value ==
std::is_signed<T2>::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 <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value &&
std::is_unsigned<T2>::value &&
LargerInt<T2, T1>::value>::type* = nullptr>
inline bool Cmp(T1 a, T2 b) {
return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b));
}
// Overload for unsigned - signed comparison that can be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_unsigned<T1>::value &&
std::is_signed<T2>::value &&
LargerInt<T1, T2>::value>::type* = nullptr>
inline bool Cmp(T1 a, T2 b) {
return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b);
}
// Overload for signed - unsigned comparison that can't be promoted to a bigger
// signed type.
template <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_signed<T1>::value &&
std::is_unsigned<T2>::value &&
!LargerInt<T2, T1>::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 <typename Op,
typename T1,
typename T2,
typename std::enable_if<std::is_unsigned<T1>::value &&
std::is_signed<T2>::value &&
!LargerInt<T1, T2>::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 <typename T1, typename T2> \
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<typename std::remove_reference<T1>::type>::value && \
std::is_integral<typename std::remove_reference<T2>::type>::value>:: \
type* = nullptr> \
inline bool name(T1 a, T2 b) { \
return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(a, b); \
} \
template <typename T1, typename T2, \
typename std::enable_if< \
!std::is_integral< \
typename std::remove_reference<T1>::type>::value || \
!std::is_integral<typename std::remove_reference<T2>::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_

View File

@ -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 <limits>
#include "webrtc/base/safe_compare.h"
#include "webrtc/test/gtest.h"
namespace rtc {
namespace {
constexpr std::uintmax_t umax = std::numeric_limits<std::uintmax_t>::max();
constexpr std::intmax_t imin = std::numeric_limits<std::intmax_t>::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<std::uintmax_t>(m1) == umax, "");
static_assert(m1 == static_cast<std::intmax_t>(umax), "");
std::pair<int, int> p1(1, 1);
std::pair<int, int> 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<unsigned>(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

View File

@ -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);