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}
diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn
index aed1158..2c25050 100644
--- a/webrtc/base/BUILD.gn
+++ b/webrtc/base/BUILD.gn
@@ -159,6 +159,7 @@
"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 aa6725d..653ed322 100644
--- a/webrtc/base/checks.h
+++ b/webrtc/base/checks.h
@@ -36,6 +36,8 @@
#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.";
@@ -96,10 +98,8 @@
// 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<decltype(a)>() \
- op std::declval<decltype(b)>()), \
- (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 @@
// 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_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 0000000..37ddf78
--- /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 <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_
diff --git a/webrtc/base/safe_compare_unittest.cc b/webrtc/base/safe_compare_unittest.cc
new file mode 100644
index 0000000..12ab469
--- /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 <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