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/BUILD.gn b/webrtc/BUILD.gn
index 9e420ba..0dd61bb 100644
--- a/webrtc/BUILD.gn
+++ b/webrtc/BUILD.gn
@@ -437,6 +437,7 @@
       "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 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
diff --git a/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc b/webrtc/modules/audio_coding/neteq/dtmf_tone_generator.cc
index 9dad2e5..947bf6d 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 @@
   }
 
   // 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 @@
   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);