Move some numeric utility code from rtc_base/ to rtc_base/numerics/

Specifically, I'm moving

  safe_compare.h
  safe_conversions.h
  safe_minmax.h

They shouldn't be part of the API, and moving them to an appropriate
subdirectory of rtc_base/ is a good way to keep track of that.

BUG=webrtc:8445

Change-Id: I458531aeb30bcf4291c4bec3bf22a2fffbf054ff
Reviewed-on: https://webrtc-review.googlesource.com/20860
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20829}
diff --git a/rtc_base/numerics/safe_compare.h b/rtc_base/numerics/safe_compare.h
new file mode 100644
index 0000000..85f0a30
--- /dev/null
+++ b/rtc_base/numerics/safe_compare.h
@@ -0,0 +1,176 @@
+/*
+ *  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 constexpr functions:
+//
+//   rtc::SafeEq  // ==
+//   rtc::SafeNe  // !=
+//   rtc::SafeLt  // <
+//   rtc::SafeLe  // <=
+//   rtc::SafeGt  // >
+//   rtc::SafeGe  // >=
+//
+// 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 RTC_BASE_NUMERICS_SAFE_COMPARE_H_
+#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/type_traits.h"
+
+namespace rtc {
+
+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>
+constexpr 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>
+constexpr 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>
+constexpr 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>
+constexpr 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>
+constexpr 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>
+constexpr 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>                                         \
+  constexpr                                                                   \
+      typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value,   \
+                              bool>::type Safe##name(T1 a, T2 b) {            \
+    /* Unary plus here turns enums into real integral types. */               \
+    return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b);               \
+  }                                                                           \
+  template <typename T1, typename T2>                                         \
+  constexpr                                                                   \
+      typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \
+                              bool>::type Safe##name(const T1& a,             \
+                                                     const 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 rtc
+
+#endif  // RTC_BASE_NUMERICS_SAFE_COMPARE_H_
diff --git a/rtc_base/numerics/safe_compare_unittest.cc b/rtc_base/numerics/safe_compare_unittest.cc
new file mode 100644
index 0000000..e7a251f
--- /dev/null
+++ b/rtc_base/numerics/safe_compare_unittest.cc
@@ -0,0 +1,394 @@
+/*
+ *  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 "rtc_base/numerics/safe_compare.h"
+#include "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), "");
+
+static const std::pair<int, int> p1(1, 1);
+static const 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 SafeLt(a, b); }
+bool TestLessThanSafe(unsigned a, unsigned b) { return SafeLt(a, b); }
+bool TestLessThanSafe(unsigned a,      int b) { return SafeLt(a, b); }
+bool TestLessThanSafe(     int a, unsigned b) { return SafeLt(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 SafeLt(a, 17); }
+bool TestLessThan17Safe( unsigned a) { return SafeLt(a, 17); }
+bool TestLessThan17uSafe(     int a) { return SafeLt(a, 17u); }
+bool TestLessThan17uSafe(unsigned a) { return SafeLt(a, 17u); }
+
+// Cases where we can't convert to a larger signed type.
+bool TestLessThanMax( intmax_t a, uintmax_t b) { return SafeLt(a, b); }
+bool TestLessThanMax(uintmax_t a,  intmax_t b) { return SafeLt(a, b); }
+bool TestLessThanMax17u( intmax_t a) { return SafeLt(a, uintmax_t{17}); }
+bool TestLessThanMax17( uintmax_t a) { return SafeLt(a,  intmax_t{17}); }
+
+// Cases where the compiler should be able to compute the result at compile
+// time.
+bool TestLessThanConst1() { return SafeLt(  -1,    1); }
+bool TestLessThanConst2() { return SafeLt(  m1, umax); }
+bool TestLessThanConst3() { return SafeLt(umax, imin); }
+bool TestLessThanConst4(unsigned a) { return SafeLt( a, -1); }
+bool TestLessThanConst5(unsigned a) { return SafeLt(-1,  a); }
+bool TestLessThanConst6(unsigned a) { return SafeLt( a,  a); }
+
+// clang-format on
+
+TEST(SafeCmpTest, Eq) {
+  static_assert(!SafeEq(-1, 2), "");
+  static_assert(!SafeEq(-1, 2u), "");
+  static_assert(!SafeEq(2, -1), "");
+  static_assert(!SafeEq(2u, -1), "");
+
+  static_assert(!SafeEq(1, 2), "");
+  static_assert(!SafeEq(1, 2u), "");
+  static_assert(!SafeEq(1u, 2), "");
+  static_assert(!SafeEq(1u, 2u), "");
+  static_assert(!SafeEq(2, 1), "");
+  static_assert(!SafeEq(2, 1u), "");
+  static_assert(!SafeEq(2u, 1), "");
+  static_assert(!SafeEq(2u, 1u), "");
+
+  static_assert(SafeEq(2, 2), "");
+  static_assert(SafeEq(2, 2u), "");
+  static_assert(SafeEq(2u, 2), "");
+  static_assert(SafeEq(2u, 2u), "");
+
+  static_assert(SafeEq(imin, imin), "");
+  static_assert(!SafeEq(imin, umax), "");
+  static_assert(!SafeEq(umax, imin), "");
+  static_assert(SafeEq(umax, umax), "");
+
+  static_assert(SafeEq(m1, m1), "");
+  static_assert(!SafeEq(m1, umax), "");
+  static_assert(!SafeEq(umax, m1), "");
+  static_assert(SafeEq(umax, umax), "");
+
+  static_assert(!SafeEq(1, 2), "");
+  static_assert(!SafeEq(1, 2.0), "");
+  static_assert(!SafeEq(1.0, 2), "");
+  static_assert(!SafeEq(1.0, 2.0), "");
+  static_assert(!SafeEq(2, 1), "");
+  static_assert(!SafeEq(2, 1.0), "");
+  static_assert(!SafeEq(2.0, 1), "");
+  static_assert(!SafeEq(2.0, 1.0), "");
+
+  static_assert(SafeEq(2, 2), "");
+  static_assert(SafeEq(2, 2.0), "");
+  static_assert(SafeEq(2.0, 2), "");
+  static_assert(SafeEq(2.0, 2.0), "");
+
+  EXPECT_TRUE(SafeEq(p1, p1));
+  EXPECT_FALSE(SafeEq(p1, p2));
+  EXPECT_FALSE(SafeEq(p2, p1));
+  EXPECT_TRUE(SafeEq(p2, p2));
+}
+
+TEST(SafeCmpTest, Ne) {
+  static_assert(SafeNe(-1, 2), "");
+  static_assert(SafeNe(-1, 2u), "");
+  static_assert(SafeNe(2, -1), "");
+  static_assert(SafeNe(2u, -1), "");
+
+  static_assert(SafeNe(1, 2), "");
+  static_assert(SafeNe(1, 2u), "");
+  static_assert(SafeNe(1u, 2), "");
+  static_assert(SafeNe(1u, 2u), "");
+  static_assert(SafeNe(2, 1), "");
+  static_assert(SafeNe(2, 1u), "");
+  static_assert(SafeNe(2u, 1), "");
+  static_assert(SafeNe(2u, 1u), "");
+
+  static_assert(!SafeNe(2, 2), "");
+  static_assert(!SafeNe(2, 2u), "");
+  static_assert(!SafeNe(2u, 2), "");
+  static_assert(!SafeNe(2u, 2u), "");
+
+  static_assert(!SafeNe(imin, imin), "");
+  static_assert(SafeNe(imin, umax), "");
+  static_assert(SafeNe(umax, imin), "");
+  static_assert(!SafeNe(umax, umax), "");
+
+  static_assert(!SafeNe(m1, m1), "");
+  static_assert(SafeNe(m1, umax), "");
+  static_assert(SafeNe(umax, m1), "");
+  static_assert(!SafeNe(umax, umax), "");
+
+  static_assert(SafeNe(1, 2), "");
+  static_assert(SafeNe(1, 2.0), "");
+  static_assert(SafeNe(1.0, 2), "");
+  static_assert(SafeNe(1.0, 2.0), "");
+  static_assert(SafeNe(2, 1), "");
+  static_assert(SafeNe(2, 1.0), "");
+  static_assert(SafeNe(2.0, 1), "");
+  static_assert(SafeNe(2.0, 1.0), "");
+
+  static_assert(!SafeNe(2, 2), "");
+  static_assert(!SafeNe(2, 2.0), "");
+  static_assert(!SafeNe(2.0, 2), "");
+  static_assert(!SafeNe(2.0, 2.0), "");
+
+  EXPECT_FALSE(SafeNe(p1, p1));
+  EXPECT_TRUE(SafeNe(p1, p2));
+  EXPECT_TRUE(SafeNe(p2, p1));
+  EXPECT_FALSE(SafeNe(p2, p2));
+}
+
+TEST(SafeCmpTest, Lt) {
+  static_assert(SafeLt(-1, 2), "");
+  static_assert(SafeLt(-1, 2u), "");
+  static_assert(!SafeLt(2, -1), "");
+  static_assert(!SafeLt(2u, -1), "");
+
+  static_assert(SafeLt(1, 2), "");
+  static_assert(SafeLt(1, 2u), "");
+  static_assert(SafeLt(1u, 2), "");
+  static_assert(SafeLt(1u, 2u), "");
+  static_assert(!SafeLt(2, 1), "");
+  static_assert(!SafeLt(2, 1u), "");
+  static_assert(!SafeLt(2u, 1), "");
+  static_assert(!SafeLt(2u, 1u), "");
+
+  static_assert(!SafeLt(2, 2), "");
+  static_assert(!SafeLt(2, 2u), "");
+  static_assert(!SafeLt(2u, 2), "");
+  static_assert(!SafeLt(2u, 2u), "");
+
+  static_assert(!SafeLt(imin, imin), "");
+  static_assert(SafeLt(imin, umax), "");
+  static_assert(!SafeLt(umax, imin), "");
+  static_assert(!SafeLt(umax, umax), "");
+
+  static_assert(!SafeLt(m1, m1), "");
+  static_assert(SafeLt(m1, umax), "");
+  static_assert(!SafeLt(umax, m1), "");
+  static_assert(!SafeLt(umax, umax), "");
+
+  static_assert(SafeLt(1, 2), "");
+  static_assert(SafeLt(1, 2.0), "");
+  static_assert(SafeLt(1.0, 2), "");
+  static_assert(SafeLt(1.0, 2.0), "");
+  static_assert(!SafeLt(2, 1), "");
+  static_assert(!SafeLt(2, 1.0), "");
+  static_assert(!SafeLt(2.0, 1), "");
+  static_assert(!SafeLt(2.0, 1.0), "");
+
+  static_assert(!SafeLt(2, 2), "");
+  static_assert(!SafeLt(2, 2.0), "");
+  static_assert(!SafeLt(2.0, 2), "");
+  static_assert(!SafeLt(2.0, 2.0), "");
+
+  EXPECT_FALSE(SafeLt(p1, p1));
+  EXPECT_TRUE(SafeLt(p1, p2));
+  EXPECT_FALSE(SafeLt(p2, p1));
+  EXPECT_FALSE(SafeLt(p2, p2));
+}
+
+TEST(SafeCmpTest, Le) {
+  static_assert(SafeLe(-1, 2), "");
+  static_assert(SafeLe(-1, 2u), "");
+  static_assert(!SafeLe(2, -1), "");
+  static_assert(!SafeLe(2u, -1), "");
+
+  static_assert(SafeLe(1, 2), "");
+  static_assert(SafeLe(1, 2u), "");
+  static_assert(SafeLe(1u, 2), "");
+  static_assert(SafeLe(1u, 2u), "");
+  static_assert(!SafeLe(2, 1), "");
+  static_assert(!SafeLe(2, 1u), "");
+  static_assert(!SafeLe(2u, 1), "");
+  static_assert(!SafeLe(2u, 1u), "");
+
+  static_assert(SafeLe(2, 2), "");
+  static_assert(SafeLe(2, 2u), "");
+  static_assert(SafeLe(2u, 2), "");
+  static_assert(SafeLe(2u, 2u), "");
+
+  static_assert(SafeLe(imin, imin), "");
+  static_assert(SafeLe(imin, umax), "");
+  static_assert(!SafeLe(umax, imin), "");
+  static_assert(SafeLe(umax, umax), "");
+
+  static_assert(SafeLe(m1, m1), "");
+  static_assert(SafeLe(m1, umax), "");
+  static_assert(!SafeLe(umax, m1), "");
+  static_assert(SafeLe(umax, umax), "");
+
+  static_assert(SafeLe(1, 2), "");
+  static_assert(SafeLe(1, 2.0), "");
+  static_assert(SafeLe(1.0, 2), "");
+  static_assert(SafeLe(1.0, 2.0), "");
+  static_assert(!SafeLe(2, 1), "");
+  static_assert(!SafeLe(2, 1.0), "");
+  static_assert(!SafeLe(2.0, 1), "");
+  static_assert(!SafeLe(2.0, 1.0), "");
+
+  static_assert(SafeLe(2, 2), "");
+  static_assert(SafeLe(2, 2.0), "");
+  static_assert(SafeLe(2.0, 2), "");
+  static_assert(SafeLe(2.0, 2.0), "");
+
+  EXPECT_TRUE(SafeLe(p1, p1));
+  EXPECT_TRUE(SafeLe(p1, p2));
+  EXPECT_FALSE(SafeLe(p2, p1));
+  EXPECT_TRUE(SafeLe(p2, p2));
+}
+
+TEST(SafeCmpTest, Gt) {
+  static_assert(!SafeGt(-1, 2), "");
+  static_assert(!SafeGt(-1, 2u), "");
+  static_assert(SafeGt(2, -1), "");
+  static_assert(SafeGt(2u, -1), "");
+
+  static_assert(!SafeGt(1, 2), "");
+  static_assert(!SafeGt(1, 2u), "");
+  static_assert(!SafeGt(1u, 2), "");
+  static_assert(!SafeGt(1u, 2u), "");
+  static_assert(SafeGt(2, 1), "");
+  static_assert(SafeGt(2, 1u), "");
+  static_assert(SafeGt(2u, 1), "");
+  static_assert(SafeGt(2u, 1u), "");
+
+  static_assert(!SafeGt(2, 2), "");
+  static_assert(!SafeGt(2, 2u), "");
+  static_assert(!SafeGt(2u, 2), "");
+  static_assert(!SafeGt(2u, 2u), "");
+
+  static_assert(!SafeGt(imin, imin), "");
+  static_assert(!SafeGt(imin, umax), "");
+  static_assert(SafeGt(umax, imin), "");
+  static_assert(!SafeGt(umax, umax), "");
+
+  static_assert(!SafeGt(m1, m1), "");
+  static_assert(!SafeGt(m1, umax), "");
+  static_assert(SafeGt(umax, m1), "");
+  static_assert(!SafeGt(umax, umax), "");
+
+  static_assert(!SafeGt(1, 2), "");
+  static_assert(!SafeGt(1, 2.0), "");
+  static_assert(!SafeGt(1.0, 2), "");
+  static_assert(!SafeGt(1.0, 2.0), "");
+  static_assert(SafeGt(2, 1), "");
+  static_assert(SafeGt(2, 1.0), "");
+  static_assert(SafeGt(2.0, 1), "");
+  static_assert(SafeGt(2.0, 1.0), "");
+
+  static_assert(!SafeGt(2, 2), "");
+  static_assert(!SafeGt(2, 2.0), "");
+  static_assert(!SafeGt(2.0, 2), "");
+  static_assert(!SafeGt(2.0, 2.0), "");
+
+  EXPECT_FALSE(SafeGt(p1, p1));
+  EXPECT_FALSE(SafeGt(p1, p2));
+  EXPECT_TRUE(SafeGt(p2, p1));
+  EXPECT_FALSE(SafeGt(p2, p2));
+}
+
+TEST(SafeCmpTest, Ge) {
+  static_assert(!SafeGe(-1, 2), "");
+  static_assert(!SafeGe(-1, 2u), "");
+  static_assert(SafeGe(2, -1), "");
+  static_assert(SafeGe(2u, -1), "");
+
+  static_assert(!SafeGe(1, 2), "");
+  static_assert(!SafeGe(1, 2u), "");
+  static_assert(!SafeGe(1u, 2), "");
+  static_assert(!SafeGe(1u, 2u), "");
+  static_assert(SafeGe(2, 1), "");
+  static_assert(SafeGe(2, 1u), "");
+  static_assert(SafeGe(2u, 1), "");
+  static_assert(SafeGe(2u, 1u), "");
+
+  static_assert(SafeGe(2, 2), "");
+  static_assert(SafeGe(2, 2u), "");
+  static_assert(SafeGe(2u, 2), "");
+  static_assert(SafeGe(2u, 2u), "");
+
+  static_assert(SafeGe(imin, imin), "");
+  static_assert(!SafeGe(imin, umax), "");
+  static_assert(SafeGe(umax, imin), "");
+  static_assert(SafeGe(umax, umax), "");
+
+  static_assert(SafeGe(m1, m1), "");
+  static_assert(!SafeGe(m1, umax), "");
+  static_assert(SafeGe(umax, m1), "");
+  static_assert(SafeGe(umax, umax), "");
+
+  static_assert(!SafeGe(1, 2), "");
+  static_assert(!SafeGe(1, 2.0), "");
+  static_assert(!SafeGe(1.0, 2), "");
+  static_assert(!SafeGe(1.0, 2.0), "");
+  static_assert(SafeGe(2, 1), "");
+  static_assert(SafeGe(2, 1.0), "");
+  static_assert(SafeGe(2.0, 1), "");
+  static_assert(SafeGe(2.0, 1.0), "");
+
+  static_assert(SafeGe(2, 2), "");
+  static_assert(SafeGe(2, 2.0), "");
+  static_assert(SafeGe(2.0, 2), "");
+  static_assert(SafeGe(2.0, 2.0), "");
+
+  EXPECT_TRUE(SafeGe(p1, p1));
+  EXPECT_FALSE(SafeGe(p1, p2));
+  EXPECT_TRUE(SafeGe(p2, p1));
+  EXPECT_TRUE(SafeGe(p2, p2));
+}
+
+TEST(SafeCmpTest, Enum) {
+  enum E1 { e1 = 13 };
+  enum { e2 = 13 };
+  enum E3 : unsigned { e3 = 13 };
+  enum : unsigned { e4 = 13 };
+  static_assert(SafeEq(13, e1), "");
+  static_assert(SafeEq(13u, e1), "");
+  static_assert(SafeEq(13, e2), "");
+  static_assert(SafeEq(13u, e2), "");
+  static_assert(SafeEq(13, e3), "");
+  static_assert(SafeEq(13u, e3), "");
+  static_assert(SafeEq(13, e4), "");
+  static_assert(SafeEq(13u, e4), "");
+}
+
+}  // namespace rtc
diff --git a/rtc_base/numerics/safe_conversions.h b/rtc_base/numerics/safe_conversions.h
new file mode 100644
index 0000000..58efcaa
--- /dev/null
+++ b/rtc_base/numerics/safe_conversions.h
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 2014 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.
+ */
+
+// Borrowed from Chromium's src/base/numerics/safe_conversions.h.
+
+#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <limits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions_impl.h"
+
+namespace rtc {
+
+// Convenience function that returns true if the supplied value is in range
+// for the destination type.
+template <typename Dst, typename Src>
+inline bool IsValueInRangeForNumericType(Src value) {
+  return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
+}
+
+// checked_cast<> and dchecked_cast<> are analogous to static_cast<> for
+// numeric types, except that they [D]CHECK that the specified numeric
+// conversion will not overflow or underflow. NaN source will always trigger
+// the [D]CHECK.
+template <typename Dst, typename Src>
+inline Dst checked_cast(Src value) {
+  RTC_CHECK(IsValueInRangeForNumericType<Dst>(value));
+  return static_cast<Dst>(value);
+}
+template <typename Dst, typename Src>
+inline Dst dchecked_cast(Src value) {
+  RTC_DCHECK(IsValueInRangeForNumericType<Dst>(value));
+  return static_cast<Dst>(value);
+}
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate rather than overflow or
+// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition.
+template <typename Dst, typename Src>
+inline Dst saturated_cast(Src value) {
+  // Optimization for floating point values, which already saturate.
+  if (std::numeric_limits<Dst>::is_iec559)
+    return static_cast<Dst>(value);
+
+  switch (internal::RangeCheck<Dst>(value)) {
+    case internal::TYPE_VALID:
+      return static_cast<Dst>(value);
+
+    case internal::TYPE_UNDERFLOW:
+      return std::numeric_limits<Dst>::min();
+
+    case internal::TYPE_OVERFLOW:
+      return std::numeric_limits<Dst>::max();
+
+    // Should fail only on attempting to assign NaN to a saturated integer.
+    case internal::TYPE_INVALID:
+      FATAL();
+      return std::numeric_limits<Dst>::max();
+  }
+
+  FATAL();
+  return static_cast<Dst>(value);
+}
+
+}  // namespace rtc
+
+#endif  // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/rtc_base/numerics/safe_conversions_impl.h b/rtc_base/numerics/safe_conversions_impl.h
new file mode 100644
index 0000000..9b4f1c6
--- /dev/null
+++ b/rtc_base/numerics/safe_conversions_impl.h
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2014 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.
+ */
+
+// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h.
+
+#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+
+#include <limits>
+
+namespace rtc {
+namespace internal {
+
+enum DstSign { DST_UNSIGNED, DST_SIGNED };
+
+enum SrcSign { SRC_UNSIGNED, SRC_SIGNED };
+
+enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE };
+
+// Helper templates to statically determine if our destination type can contain
+// all values represented by the source type.
+
+template <typename Dst,
+          typename Src,
+          DstSign IsDstSigned =
+              std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
+          SrcSign IsSrcSigned =
+              std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED>
+struct StaticRangeCheck {};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> {
+  typedef std::numeric_limits<Dst> DstLimits;
+  typedef std::numeric_limits<Src> SrcLimits;
+  // Compare based on max_exponent, which we must compute for integrals.
+  static const size_t kDstMaxExponent =
+      DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
+  static const size_t kSrcMaxExponent =
+      SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1);
+  static const DstRange value =
+      kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> {
+  static const DstRange value =
+      sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> {
+  typedef std::numeric_limits<Dst> DstLimits;
+  typedef std::numeric_limits<Src> SrcLimits;
+  // Compare based on max_exponent, which we must compute for integrals.
+  static const size_t kDstMaxExponent =
+      DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
+  static const size_t kSrcMaxExponent = sizeof(Src) * 8;
+  static const DstRange value =
+      kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> {
+  static const DstRange value = OVERLAPS_RANGE;
+};
+
+enum RangeCheckResult {
+  TYPE_VALID = 0,      // Value can be represented by the destination type.
+  TYPE_UNDERFLOW = 1,  // Value would overflow.
+  TYPE_OVERFLOW = 2,   // Value would underflow.
+  TYPE_INVALID = 3     // Source value is invalid (i.e. NaN).
+};
+
+// This macro creates a RangeCheckResult from an upper and lower bound
+// check by taking advantage of the fact that only NaN can be out of range in
+// both directions at once.
+#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \
+  RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) |                \
+                   ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
+
+template <typename Dst,
+          typename Src,
+          DstSign IsDstSigned =
+              std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
+          SrcSign IsSrcSigned =
+              std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED,
+          DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value>
+struct RangeCheckImpl {};
+
+// The following templates are for ranges that must be verified at runtime. We
+// split it into checks based on signedness to avoid confusing casts and
+// compiler warnings on signed an unsigned comparisons.
+
+// Dst range always contains the result: nothing to check.
+template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned>
+struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> {
+  static RangeCheckResult Check(Src value) { return TYPE_VALID; }
+};
+
+// Signed to signed narrowing.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
+  static RangeCheckResult Check(Src value) {
+    typedef std::numeric_limits<Dst> DstLimits;
+    return DstLimits::is_iec559
+               ? BASE_NUMERIC_RANGE_CHECK_RESULT(
+                     value <= static_cast<Src>(DstLimits::max()),
+                     value >= static_cast<Src>(DstLimits::max() * -1))
+               : BASE_NUMERIC_RANGE_CHECK_RESULT(
+                     value <= static_cast<Src>(DstLimits::max()),
+                     value >= static_cast<Src>(DstLimits::min()));
+  }
+};
+
+// Unsigned to unsigned narrowing.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
+  static RangeCheckResult Check(Src value) {
+    typedef std::numeric_limits<Dst> DstLimits;
+    return BASE_NUMERIC_RANGE_CHECK_RESULT(
+        value <= static_cast<Src>(DstLimits::max()), true);
+  }
+};
+
+// Unsigned to signed.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
+  static RangeCheckResult Check(Src value) {
+    typedef std::numeric_limits<Dst> DstLimits;
+    return sizeof(Dst) > sizeof(Src)
+               ? TYPE_VALID
+               : BASE_NUMERIC_RANGE_CHECK_RESULT(
+                     value <= static_cast<Src>(DstLimits::max()), true);
+  }
+};
+
+// Signed to unsigned.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
+  static RangeCheckResult Check(Src value) {
+    typedef std::numeric_limits<Dst> DstLimits;
+    typedef std::numeric_limits<Src> SrcLimits;
+    // Compare based on max_exponent, which we must compute for integrals.
+    static const size_t kDstMaxExponent = sizeof(Dst) * 8;
+    static const size_t kSrcMaxExponent =
+        SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1);
+    return (kDstMaxExponent >= kSrcMaxExponent)
+               ? BASE_NUMERIC_RANGE_CHECK_RESULT(true,
+                                                 value >= static_cast<Src>(0))
+               : BASE_NUMERIC_RANGE_CHECK_RESULT(
+                     value <= static_cast<Src>(DstLimits::max()),
+                     value >= static_cast<Src>(0));
+  }
+};
+
+template <typename Dst, typename Src>
+inline RangeCheckResult RangeCheck(Src value) {
+  static_assert(std::numeric_limits<Src>::is_specialized,
+                "argument must be numeric");
+  static_assert(std::numeric_limits<Dst>::is_specialized,
+                "result must be numeric");
+  return RangeCheckImpl<Dst, Src>::Check(value);
+}
+
+}  // namespace internal
+}  // namespace rtc
+
+#endif  // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/rtc_base/numerics/safe_minmax.h b/rtc_base/numerics/safe_minmax.h
new file mode 100644
index 0000000..8d00afb
--- /dev/null
+++ b/rtc_base/numerics/safe_minmax.h
@@ -0,0 +1,335 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+// Minimum and maximum
+// ===================
+//
+//   rtc::SafeMin(x, y)
+//   rtc::SafeMax(x, y)
+//
+// (These are both constexpr.)
+//
+// Accept two arguments of either any two integral or any two floating-point
+// types, and return the smaller and larger value, respectively, with no
+// truncation or wrap-around. If only one of the input types is statically
+// guaranteed to be able to represent the result, the return type is that type;
+// if either one would do, the result type is the smaller type. (One of these
+// two cases always applies.)
+//
+//   * The case with one floating-point and one integral type is not allowed,
+//     because the floating-point type will have greater range, but may not
+//     have sufficient precision to represent the integer value exactly.)
+//
+// Clamp (a.k.a. constrain to a given interval)
+// ============================================
+//
+//   rtc::SafeClamp(x, a, b)
+//
+// Accepts three arguments of any mix of integral types or any mix of
+// floating-point types, and returns the value in the closed interval [a, b]
+// that is closest to x (that is, if x < a it returns a; if x > b it returns b;
+// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is
+// no truncation or wrap-around. The result type
+//
+//   1. is statically guaranteed to be able to represent the result;
+//
+//   2. is no larger than the largest of the three argument types; and
+//
+//   3. has the same signedness as the type of the third argument, if this is
+//      possible without violating the First or Second Law.
+//
+// There is always at least one type that meets criteria 1 and 2. If more than
+// one type meets these criteria equally well, the result type is one of the
+// types that is smallest. Note that unlike SafeMin() and SafeMax(),
+// SafeClamp() will sometimes pick a return type that isn't the type of any of
+// its arguments.
+//
+//   * In this context, a type A is smaller than a type B if it has a smaller
+//     range; that is, if A::max() - A::min() < B::max() - B::min(). For
+//     example, int8_t < int16_t == uint16_t < int32_t, and all integral types
+//     are smaller than all floating-point types.)
+//
+//   * As for SafeMin and SafeMax, mixing integer and floating-point arguments
+//     is not allowed, because floating-point types have greater range than
+//     integer types, but do not have sufficient precision to represent the
+//     values of most integer types exactly.
+//
+// Requesting a specific return type
+// =================================
+//
+// All three functions allow callers to explicitly specify the return type as a
+// template parameter, overriding the default return type. E.g.
+//
+//   rtc::SafeMin<int>(x, y)  // returns an int
+//
+// If the requested type is statically guaranteed to be able to represent the
+// result, then everything's fine, and the return type is as requested. But if
+// the requested type is too small, a static_assert is triggered.
+
+#ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_
+#define RTC_BASE_NUMERICS_SAFE_MINMAX_H_
+
+#include <limits>
+#include <type_traits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_compare.h"
+#include "rtc_base/type_traits.h"
+
+namespace rtc {
+
+namespace safe_minmax_impl {
+
+// Make the range of a type available via something other than a constexpr
+// function, to work around MSVC limitations. See
+// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
+template <typename T>
+struct Limits {
+  static constexpr T lowest = std::numeric_limits<T>::lowest();
+  static constexpr T max = std::numeric_limits<T>::max();
+};
+
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct UnderlyingType;
+
+template <typename T>
+struct UnderlyingType<T, false> {
+  using type = T;
+};
+
+template <typename T>
+struct UnderlyingType<T, true> {
+  using type = typename std::underlying_type<T>::type;
+};
+
+// Given two types T1 and T2, find types that can hold the smallest (in
+// ::min_t) and the largest (in ::max_t) of the two values.
+template <typename T1,
+          typename T2,
+          bool int1 = IsIntlike<T1>::value,
+          bool int2 = IsIntlike<T2>::value>
+struct MType {
+  static_assert(int1 == int2,
+                "You may not mix integral and floating-point arguments");
+};
+
+// Specialization for when neither type is integral (and therefore presumably
+// floating-point).
+template <typename T1, typename T2>
+struct MType<T1, T2, false, false> {
+  using min_t = typename std::common_type<T1, T2>::type;
+  static_assert(std::is_same<min_t, T1>::value ||
+                    std::is_same<min_t, T2>::value,
+                "");
+
+  using max_t = typename std::common_type<T1, T2>::type;
+  static_assert(std::is_same<max_t, T1>::value ||
+                    std::is_same<max_t, T2>::value,
+                "");
+};
+
+// Specialization for when both types are integral.
+template <typename T1, typename T2>
+struct MType<T1, T2, true, true> {
+  // The type with the lowest minimum value. In case of a tie, the type with
+  // the lowest maximum value. In case that too is a tie, the types have the
+  // same range, and we arbitrarily pick T1.
+  using min_t = typename std::conditional<
+      SafeLt(Limits<T1>::lowest, Limits<T2>::lowest),
+      T1,
+      typename std::conditional<
+          SafeGt(Limits<T1>::lowest, Limits<T2>::lowest),
+          T2,
+          typename std::conditional<SafeLe(Limits<T1>::max, Limits<T2>::max),
+                                    T1,
+                                    T2>::type>::type>::type;
+  static_assert(std::is_same<min_t, T1>::value ||
+                    std::is_same<min_t, T2>::value,
+                "");
+
+  // The type with the highest maximum value. In case of a tie, the types have
+  // the same range (because in C++, integer types with the same maximum also
+  // have the same minimum).
+  static_assert(SafeNe(Limits<T1>::max, Limits<T2>::max) ||
+                    SafeEq(Limits<T1>::lowest, Limits<T2>::lowest),
+                "integer types with the same max should have the same min");
+  using max_t = typename std::
+      conditional<SafeGe(Limits<T1>::max, Limits<T2>::max), T1, T2>::type;
+  static_assert(std::is_same<max_t, T1>::value ||
+                    std::is_same<max_t, T2>::value,
+                "");
+};
+
+// A dummy type that we pass around at compile time but never actually use.
+// Declared but not defined.
+struct DefaultType;
+
+// ::type is A, except we fall back to B if A is DefaultType. We static_assert
+// that the chosen type can hold all values that B can hold.
+template <typename A, typename B>
+struct TypeOr {
+  using type = typename std::
+      conditional<std::is_same<A, DefaultType>::value, B, A>::type;
+  static_assert(SafeLe(Limits<type>::lowest, Limits<B>::lowest) &&
+                    SafeGe(Limits<type>::max, Limits<B>::max),
+                "The specified type isn't large enough");
+  static_assert(IsIntlike<type>::value == IsIntlike<B>::value &&
+                    std::is_floating_point<type>::value ==
+                        std::is_floating_point<type>::value,
+                "float<->int conversions not allowed");
+};
+
+}  // namespace safe_minmax_impl
+
+template <
+    typename R = safe_minmax_impl::DefaultType,
+    typename T1 = safe_minmax_impl::DefaultType,
+    typename T2 = safe_minmax_impl::DefaultType,
+    typename R2 = typename safe_minmax_impl::TypeOr<
+        R,
+        typename safe_minmax_impl::MType<
+            typename safe_minmax_impl::UnderlyingType<T1>::type,
+            typename safe_minmax_impl::UnderlyingType<T2>::type>::min_t>::type>
+constexpr R2 SafeMin(T1 a, T2 b) {
+  static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
+                "The first argument must be integral or floating-point");
+  static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
+                "The second argument must be integral or floating-point");
+  return SafeLt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
+}
+
+template <
+    typename R = safe_minmax_impl::DefaultType,
+    typename T1 = safe_minmax_impl::DefaultType,
+    typename T2 = safe_minmax_impl::DefaultType,
+    typename R2 = typename safe_minmax_impl::TypeOr<
+        R,
+        typename safe_minmax_impl::MType<
+            typename safe_minmax_impl::UnderlyingType<T1>::type,
+            typename safe_minmax_impl::UnderlyingType<T2>::type>::max_t>::type>
+constexpr R2 SafeMax(T1 a, T2 b) {
+  static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
+                "The first argument must be integral or floating-point");
+  static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
+                "The second argument must be integral or floating-point");
+  return SafeGt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
+}
+
+namespace safe_minmax_impl {
+
+// Given three types T, L, and H, let ::type be a suitable return value for
+// SafeClamp(T, L, H). See the docs at the top of this file for details.
+template <typename T,
+          typename L,
+          typename H,
+          bool int1 = IsIntlike<T>::value,
+          bool int2 = IsIntlike<L>::value,
+          bool int3 = IsIntlike<H>::value>
+struct ClampType {
+  static_assert(int1 == int2 && int1 == int3,
+                "You may not mix integral and floating-point arguments");
+};
+
+// Specialization for when all three types are floating-point.
+template <typename T, typename L, typename H>
+struct ClampType<T, L, H, false, false, false> {
+  using type = typename std::common_type<T, L, H>::type;
+};
+
+// Specialization for when all three types are integral.
+template <typename T, typename L, typename H>
+struct ClampType<T, L, H, true, true, true> {
+ private:
+  // Range of the return value. The return type must be able to represent this
+  // full range.
+  static constexpr auto r_min =
+      SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest));
+  static constexpr auto r_max =
+      SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max));
+
+  // Is the given type an acceptable return type? (That is, can it represent
+  // all possible return values, and is it no larger than the largest of the
+  // input types?)
+  template <typename A>
+  struct AcceptableType {
+   private:
+    static constexpr bool not_too_large = sizeof(A) <= sizeof(L) ||
+                                          sizeof(A) <= sizeof(H) ||
+                                          sizeof(A) <= sizeof(T);
+    static constexpr bool range_contained =
+        SafeLe(Limits<A>::lowest, r_min) && SafeLe(r_max, Limits<A>::max);
+
+   public:
+    static constexpr bool value = not_too_large && range_contained;
+  };
+
+  using best_signed_type = typename std::conditional<
+      AcceptableType<int8_t>::value,
+      int8_t,
+      typename std::conditional<
+          AcceptableType<int16_t>::value,
+          int16_t,
+          typename std::conditional<AcceptableType<int32_t>::value,
+                                    int32_t,
+                                    int64_t>::type>::type>::type;
+
+  using best_unsigned_type = typename std::conditional<
+      AcceptableType<uint8_t>::value,
+      uint8_t,
+      typename std::conditional<
+          AcceptableType<uint16_t>::value,
+          uint16_t,
+          typename std::conditional<AcceptableType<uint32_t>::value,
+                                    uint32_t,
+                                    uint64_t>::type>::type>::type;
+
+ public:
+  // Pick the best type, preferring the same signedness as T but falling back
+  // to the other one if necessary.
+  using type = typename std::conditional<
+      std::is_signed<T>::value,
+      typename std::conditional<AcceptableType<best_signed_type>::value,
+                                best_signed_type,
+                                best_unsigned_type>::type,
+      typename std::conditional<AcceptableType<best_unsigned_type>::value,
+                                best_unsigned_type,
+                                best_signed_type>::type>::type;
+  static_assert(AcceptableType<type>::value, "");
+};
+
+}  // namespace safe_minmax_impl
+
+template <
+    typename R = safe_minmax_impl::DefaultType,
+    typename T = safe_minmax_impl::DefaultType,
+    typename L = safe_minmax_impl::DefaultType,
+    typename H = safe_minmax_impl::DefaultType,
+    typename R2 = typename safe_minmax_impl::TypeOr<
+        R,
+        typename safe_minmax_impl::ClampType<
+            typename safe_minmax_impl::UnderlyingType<T>::type,
+            typename safe_minmax_impl::UnderlyingType<L>::type,
+            typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type>
+R2 SafeClamp(T x, L min, H max) {
+  static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value,
+                "The first argument must be integral or floating-point");
+  static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value,
+                "The second argument must be integral or floating-point");
+  static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value,
+                "The third argument must be integral or floating-point");
+  RTC_DCHECK_LE(min, max);
+  return SafeLe(x, min)
+             ? static_cast<R2>(min)
+             : SafeGe(x, max) ? static_cast<R2>(max) : static_cast<R2>(x);
+}
+
+}  // namespace rtc
+
+#endif  // RTC_BASE_NUMERICS_SAFE_MINMAX_H_
diff --git a/rtc_base/numerics/safe_minmax_unittest.cc b/rtc_base/numerics/safe_minmax_unittest.cc
new file mode 100644
index 0000000..72d23b6
--- /dev/null
+++ b/rtc_base/numerics/safe_minmax_unittest.cc
@@ -0,0 +1,344 @@
+/*
+ *  Copyright 2017 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 <algorithm>
+#include <limits>
+
+#include "rtc_base/numerics/safe_minmax.h"
+#include "test/gtest.h"
+
+namespace rtc {
+
+namespace {
+
+// Functions that check that SafeMin(), SafeMax(), and SafeClamp() return the
+// specified type. The functions that end in "R" use an explicitly given return
+// type.
+
+template <typename T1, typename T2, typename Tmin, typename Tmax>
+constexpr bool TypeCheckMinMax() {
+  return std::is_same<decltype(SafeMin(std::declval<T1>(), std::declval<T2>())),
+                      Tmin>::value &&
+         std::is_same<decltype(SafeMax(std::declval<T1>(), std::declval<T2>())),
+                      Tmax>::value;
+}
+
+template <typename T1, typename T2, typename R>
+constexpr bool TypeCheckMinR() {
+  return std::is_same<
+      decltype(SafeMin<R>(std::declval<T1>(), std::declval<T2>())), R>::value;
+}
+
+template <typename T1, typename T2, typename R>
+constexpr bool TypeCheckMaxR() {
+  return std::is_same<
+      decltype(SafeMax<R>(std::declval<T1>(), std::declval<T2>())), R>::value;
+}
+
+template <typename T, typename L, typename H, typename R>
+constexpr bool TypeCheckClamp() {
+  return std::is_same<decltype(SafeClamp(std::declval<T>(), std::declval<L>(),
+                                         std::declval<H>())),
+                      R>::value;
+}
+
+template <typename T, typename L, typename H, typename R>
+constexpr bool TypeCheckClampR() {
+  return std::is_same<decltype(SafeClamp<R>(std::declval<T>(),
+                                            std::declval<L>(),
+                                            std::declval<H>())),
+                      R>::value;
+}
+
+// clang-format off
+
+// SafeMin/SafeMax: Check that all combinations of signed/unsigned 8/64 bits
+// give the correct default result type.
+static_assert(TypeCheckMinMax<  int8_t,   int8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckMinMax<  int8_t,  uint8_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckMinMax<  int8_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckMinMax<  int8_t, uint64_t,   int8_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax< uint8_t,   int8_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckMinMax< uint8_t,  uint8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckMinMax< uint8_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckMinMax< uint8_t, uint64_t,  uint8_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax< int64_t,   int8_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckMinMax< int64_t,  uint8_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckMinMax< int64_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckMinMax< int64_t, uint64_t,  int64_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax<uint64_t,   int8_t,   int8_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax<uint64_t,  uint8_t,  uint8_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax<uint64_t,  int64_t,  int64_t, uint64_t>(), "");
+static_assert(TypeCheckMinMax<uint64_t, uint64_t, uint64_t, uint64_t>(), "");
+
+// SafeClamp: Check that all combinations of signed/unsigned 8/64 bits give the
+// correct result type.
+static_assert(TypeCheckClamp<  int8_t,   int8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,   int8_t,  uint8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,   int8_t,  int64_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,   int8_t, uint64_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  uint8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  uint8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  uint8_t,  int64_t,  int16_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  uint8_t, uint64_t,  int16_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  int64_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  int64_t,  uint8_t,  int16_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp<  int8_t,  int64_t, uint64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp<  int8_t, uint64_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<  int8_t, uint64_t,  uint8_t,  int16_t>(), "");
+static_assert(TypeCheckClamp<  int8_t, uint64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp<  int8_t, uint64_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,   int8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,   int8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,   int8_t,  int64_t,  int16_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,   int8_t, uint64_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  uint8_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  uint8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  uint8_t,  int64_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  uint8_t, uint64_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  int64_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  int64_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< uint8_t,  int64_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp< uint8_t, uint64_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t, uint64_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp< uint8_t, uint64_t,  int64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp< uint8_t, uint64_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,   int8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp< int64_t,   int8_t,  uint8_t,  int16_t>(), "");
+static_assert(TypeCheckClamp< int64_t,   int8_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,   int8_t, uint64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  uint8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  uint8_t,  uint8_t,  int16_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  uint8_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  uint8_t, uint64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  int64_t,   int8_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  int64_t,  uint8_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t,  int64_t, uint64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t, uint64_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp< int64_t, uint64_t,  uint8_t,  int16_t>(), "");
+static_assert(TypeCheckClamp< int64_t, uint64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp< int64_t, uint64_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,   int8_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,   int8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,   int8_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,   int8_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  uint8_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  uint8_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  uint8_t,  int64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  uint8_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  int64_t,   int8_t,   int8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  int64_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  int64_t,  int64_t,  int64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t,  int64_t, uint64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t, uint64_t,   int8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t, uint64_t,  uint8_t,  uint8_t>(), "");
+static_assert(TypeCheckClamp<uint64_t, uint64_t,  int64_t, uint64_t>(), "");
+static_assert(TypeCheckClamp<uint64_t, uint64_t, uint64_t, uint64_t>(), "");
+
+enum DefaultE { kFoo = -17 };
+enum UInt8E : uint8_t { kBar = 17 };
+
+// SafeMin/SafeMax: Check that we can use enum types.
+static_assert(TypeCheckMinMax<unsigned, unsigned, unsigned, unsigned>(), "");
+static_assert(TypeCheckMinMax<unsigned, DefaultE,      int, unsigned>(), "");
+static_assert(TypeCheckMinMax<unsigned,   UInt8E,  uint8_t, unsigned>(), "");
+static_assert(TypeCheckMinMax<DefaultE, unsigned,      int, unsigned>(), "");
+static_assert(TypeCheckMinMax<DefaultE, DefaultE,      int,      int>(), "");
+static_assert(TypeCheckMinMax<DefaultE,   UInt8E,      int,      int>(), "");
+static_assert(TypeCheckMinMax<  UInt8E, unsigned,  uint8_t, unsigned>(), "");
+static_assert(TypeCheckMinMax<  UInt8E, DefaultE,     int,       int>(), "");
+static_assert(TypeCheckMinMax<  UInt8E,   UInt8E,  uint8_t,  uint8_t>(), "");
+
+// SafeClamp: Check that we can use enum types.
+static_assert(TypeCheckClamp<unsigned, unsigned, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<unsigned, unsigned, DefaultE, unsigned>(), "");
+static_assert(TypeCheckClamp<unsigned, unsigned,   UInt8E,  uint8_t>(), "");
+static_assert(TypeCheckClamp<unsigned, DefaultE, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<unsigned, DefaultE, DefaultE,      int>(), "");
+static_assert(TypeCheckClamp<unsigned, DefaultE,   UInt8E,  uint8_t>(), "");
+static_assert(TypeCheckClamp<unsigned,   UInt8E, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<unsigned,   UInt8E, DefaultE, unsigned>(), "");
+static_assert(TypeCheckClamp<unsigned,   UInt8E,   UInt8E,  uint8_t>(), "");
+static_assert(TypeCheckClamp<DefaultE, unsigned, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<DefaultE, unsigned, DefaultE,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE, unsigned,   UInt8E,  int16_t>(), "");
+static_assert(TypeCheckClamp<DefaultE, DefaultE, unsigned,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE, DefaultE, DefaultE,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE, DefaultE,   UInt8E,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE,   UInt8E, unsigned,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE,   UInt8E, DefaultE,      int>(), "");
+static_assert(TypeCheckClamp<DefaultE,   UInt8E,   UInt8E,  int16_t>(), "");
+static_assert(TypeCheckClamp<  UInt8E, unsigned, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<  UInt8E, unsigned, DefaultE, unsigned>(), "");
+static_assert(TypeCheckClamp<  UInt8E, unsigned,   UInt8E,  uint8_t>(), "");
+static_assert(TypeCheckClamp<  UInt8E, DefaultE, unsigned, unsigned>(), "");
+static_assert(TypeCheckClamp<  UInt8E, DefaultE, DefaultE,      int>(), "");
+static_assert(TypeCheckClamp<  UInt8E, DefaultE,   UInt8E,  uint8_t>(), "");
+static_assert(TypeCheckClamp<  UInt8E,   UInt8E, unsigned,  uint8_t>(), "");
+static_assert(TypeCheckClamp<  UInt8E,   UInt8E, DefaultE,  uint8_t>(), "");
+static_assert(TypeCheckClamp<  UInt8E,   UInt8E,   UInt8E,  uint8_t>(), "");
+
+using ld = long double;
+
+// SafeMin/SafeMax: Check that all floating-point combinations give the
+// correct result type.
+static_assert(TypeCheckMinMax< float,  float,  float,  float>(), "");
+static_assert(TypeCheckMinMax< float, double, double, double>(), "");
+static_assert(TypeCheckMinMax< float,     ld,     ld,     ld>(), "");
+static_assert(TypeCheckMinMax<double,  float, double, double>(), "");
+static_assert(TypeCheckMinMax<double, double, double, double>(), "");
+static_assert(TypeCheckMinMax<double,     ld,     ld,     ld>(), "");
+static_assert(TypeCheckMinMax<    ld,  float,     ld,     ld>(), "");
+static_assert(TypeCheckMinMax<    ld, double,     ld,     ld>(), "");
+static_assert(TypeCheckMinMax<    ld,     ld,     ld,     ld>(), "");
+
+// SafeClamp: Check that all floating-point combinations give the correct
+// result type.
+static_assert(TypeCheckClamp< float,  float,  float,  float>(), "");
+static_assert(TypeCheckClamp< float,  float, double, double>(), "");
+static_assert(TypeCheckClamp< float,  float,     ld,     ld>(), "");
+static_assert(TypeCheckClamp< float, double,  float, double>(), "");
+static_assert(TypeCheckClamp< float, double, double, double>(), "");
+static_assert(TypeCheckClamp< float, double,     ld,     ld>(), "");
+static_assert(TypeCheckClamp< float,     ld,  float,     ld>(), "");
+static_assert(TypeCheckClamp< float,     ld, double,     ld>(), "");
+static_assert(TypeCheckClamp< float,     ld,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<double,  float,  float, double>(), "");
+static_assert(TypeCheckClamp<double,  float, double, double>(), "");
+static_assert(TypeCheckClamp<double,  float,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<double, double,  float, double>(), "");
+static_assert(TypeCheckClamp<double, double, double, double>(), "");
+static_assert(TypeCheckClamp<double, double,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<double,     ld,  float,     ld>(), "");
+static_assert(TypeCheckClamp<double,     ld, double,     ld>(), "");
+static_assert(TypeCheckClamp<double,     ld,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,  float,  float,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,  float, double,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,  float,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<    ld, double,  float,     ld>(), "");
+static_assert(TypeCheckClamp<    ld, double, double,     ld>(), "");
+static_assert(TypeCheckClamp<    ld, double,     ld,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,     ld,  float,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,     ld, double,     ld>(), "");
+static_assert(TypeCheckClamp<    ld,     ld,     ld,     ld>(), "");
+
+// clang-format on
+
+// SafeMin/SafeMax: Check some cases of explicitly specified return type. The
+// commented-out lines give compilation errors due to the requested return type
+// being too small or requiring an int<->float conversion.
+static_assert(TypeCheckMinR<int8_t, int8_t, int16_t>(), "");
+// static_assert(TypeCheckMinR<int8_t, int8_t, float>(), "");
+static_assert(TypeCheckMinR<uint32_t, uint64_t, uint32_t>(), "");
+// static_assert(TypeCheckMaxR<uint64_t, float, float>(), "");
+// static_assert(TypeCheckMaxR<uint64_t, double, float>(), "");
+static_assert(TypeCheckMaxR<uint32_t, int32_t, uint32_t>(), "");
+// static_assert(TypeCheckMaxR<uint32_t, int32_t, int32_t>(), "");
+
+// SafeClamp: Check some cases of explicitly specified return type. The
+// commented-out lines give compilation errors due to the requested return type
+// being too small.
+static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int16_t>(), "");
+static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int32_t>(), "");
+// static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, uint32_t>(), "");
+
+template <typename T1, typename T2, typename Tmin, typename Tmax>
+constexpr bool CheckMinMax(T1 a, T2 b, Tmin min, Tmax max) {
+  return TypeCheckMinMax<T1, T2, Tmin, Tmax>() && SafeMin(a, b) == min &&
+         SafeMax(a, b) == max;
+}
+
+template <typename T, typename L, typename H, typename R>
+bool CheckClamp(T x, L min, H max, R clamped) {
+  return TypeCheckClamp<T, L, H, R>() && SafeClamp(x, min, max) == clamped;
+}
+
+// SafeMin/SafeMax: Check a few values.
+static_assert(CheckMinMax(int8_t{1}, int8_t{-1}, int8_t{-1}, int8_t{1}), "");
+static_assert(CheckMinMax(uint8_t{1}, int8_t{-1}, int8_t{-1}, uint8_t{1}), "");
+static_assert(CheckMinMax(uint8_t{5}, uint64_t{2}, uint8_t{2}, uint64_t{5}),
+              "");
+static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
+                          std::numeric_limits<uint32_t>::max(),
+                          std::numeric_limits<int32_t>::min(),
+                          std::numeric_limits<uint32_t>::max()),
+              "");
+static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
+                          std::numeric_limits<uint16_t>::max(),
+                          std::numeric_limits<int32_t>::min(),
+                          int32_t{std::numeric_limits<uint16_t>::max()}),
+              "");
+// static_assert(CheckMinMax(1.f, 2, 1.f, 2.f), "");
+static_assert(CheckMinMax(1.f, 0.0, 0.0, 1.0), "");
+
+// SafeClamp: Check a few values.
+TEST(SafeMinmaxTest, Clamp) {
+  EXPECT_TRUE(CheckClamp(int32_t{-1000000}, std::numeric_limits<int16_t>::min(),
+                         std::numeric_limits<int16_t>::max(),
+                         std::numeric_limits<int16_t>::min()));
+  EXPECT_TRUE(CheckClamp(uint32_t{1000000}, std::numeric_limits<int16_t>::min(),
+                         std::numeric_limits<int16_t>::max(),
+                         std::numeric_limits<int16_t>::max()));
+  EXPECT_TRUE(CheckClamp(3.f, -1.0, 1.f, 1.0));
+  EXPECT_TRUE(CheckClamp(3.0, -1.f, 1.f, 1.0));
+}
+
+}  // namespace
+
+// 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 Test*Safe
+// functions result in exactly the same code as their Test*Ref counterparts,
+// and that (2) the mixed-signedness Test*Safe functions have just a few extra
+// arithmetic and logic instructions (but no extra control flow instructions).
+
+// clang-format off
+int32_t  TestMinRef(  int32_t a,  int32_t b) { return std::min(a, b); }
+uint32_t TestMinRef( uint32_t a, uint32_t b) { return std::min(a, b); }
+int32_t  TestMinSafe( int32_t a,  int32_t b) { return SafeMin(a, b); }
+int32_t  TestMinSafe( int32_t a, uint32_t b) { return SafeMin(a, b); }
+int32_t  TestMinSafe(uint32_t a,  int32_t b) { return SafeMin(a, b); }
+uint32_t TestMinSafe(uint32_t a, uint32_t b) { return SafeMin(a, b); }
+// clang-format on
+
+int32_t TestClampRef(int32_t x, int32_t a, int32_t b) {
+  return std::max(a, std::min(x, b));
+}
+uint32_t TestClampRef(uint32_t x, uint32_t a, uint32_t b) {
+  return std::max(a, std::min(x, b));
+}
+int32_t TestClampSafe(int32_t x, int32_t a, int32_t b) {
+  return SafeClamp(x, a, b);
+}
+int32_t TestClampSafe(int32_t x, int32_t a, uint32_t b) {
+  return SafeClamp(x, a, b);
+}
+int32_t TestClampSafe(int32_t x, uint32_t a, int32_t b) {
+  return SafeClamp(x, a, b);
+}
+uint32_t TestClampSafe(int32_t x, uint32_t a, uint32_t b) {
+  return SafeClamp(x, a, b);
+}
+int32_t TestClampSafe(uint32_t x, int32_t a, int32_t b) {
+  return SafeClamp(x, a, b);
+}
+uint32_t TestClampSafe(uint32_t x, int32_t a, uint32_t b) {
+  return SafeClamp(x, a, b);
+}
+int32_t TestClampSafe(uint32_t x, uint32_t a, int32_t b) {
+  return SafeClamp(x, a, b);
+}
+uint32_t TestClampSafe(uint32_t x, uint32_t a, uint32_t b) {
+  return SafeClamp(x, a, b);
+}
+
+}  // namespace rtc
diff --git a/rtc_base/numerics/sequence_number_util.h b/rtc_base/numerics/sequence_number_util.h
index 9dbd812..4a39347 100644
--- a/rtc_base/numerics/sequence_number_util.h
+++ b/rtc_base/numerics/sequence_number_util.h
@@ -16,7 +16,7 @@
 
 #include "api/optional.h"
 #include "rtc_base/mod_ops.h"
-#include "rtc_base/safe_compare.h"
+#include "rtc_base/numerics/safe_compare.h"
 
 namespace webrtc {