Add SafeClamp(), which accepts args of different types

Specifically, just like SafeMin() and SafeMax() it handles all
combinations of integer and all
combinations of floating-point arguments by picking a
result type that is guaranteed to be able to hold the result.

This CL also replaces a bunch of std::min + std:max call pairs with
calls to SafeClamp()---the ones that could easily be found by grep
because "min" and "max" were on the same line. :-)

BUG=webrtc:7459

Review-Url: https://codereview.webrtc.org/2808513003
Cr-Commit-Position: refs/heads/master@{#18542}
diff --git a/webrtc/base/safe_minmax.h b/webrtc/base/safe_minmax.h
index 16638ef..5d6a7d0 100644
--- a/webrtc/base/safe_minmax.h
+++ b/webrtc/base/safe_minmax.h
@@ -14,6 +14,8 @@
 //   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
@@ -21,14 +23,48 @@
 // 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.)
+//   * 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
 // =================================
 //
-// Both functions allow callers to explicitly specify the return type as a
+// 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
@@ -187,6 +223,115 @@
   return safe_cmp::Gt(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 =
+        safe_cmp::Le(Limits<A>::lowest, r_min) &&
+        safe_cmp::Le(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 safe_cmp::Le(x, min)
+             ? static_cast<R2>(min)
+             : safe_cmp::Ge(x, max) ? static_cast<R2>(max) : static_cast<R2>(x);
+}
+
 }  // namespace rtc
 
 #endif  // WEBRTC_BASE_SAFE_MINMAX_H_
diff --git a/webrtc/base/safe_minmax_unittest.cc b/webrtc/base/safe_minmax_unittest.cc
index 519158b..eb0fe80 100644
--- a/webrtc/base/safe_minmax_unittest.cc
+++ b/webrtc/base/safe_minmax_unittest.cc
@@ -18,8 +18,9 @@
 
 namespace {
 
-// Functions that check that SafeMin() and SafeMax() return the specified type.
-// The functions that end in "R" use an explicitly given return type.
+// 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() {
@@ -41,6 +42,21 @@
       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
@@ -62,6 +78,73 @@
 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 };
 
@@ -76,6 +159,35 @@
 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
@@ -90,6 +202,36 @@
 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
@@ -103,12 +245,24 @@
 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}), "");
@@ -127,22 +281,64 @@
 // 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
 
-// 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
+// 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/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index 64df679..be32aef 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -20,6 +20,7 @@
 #include "webrtc/base/numerics/exp_filter.h"
 #include "webrtc/base/protobuf_utils.h"
 #include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/base/string_to_number.h"
 #include "webrtc/base/timeutils.h"
 #include "webrtc/common_types.h"
@@ -690,8 +691,8 @@
 }
 
 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
-  config_.bitrate_bps = rtc::Optional<int>(std::max(
-      std::min(bits_per_second, kOpusMaxBitrateBps), kOpusMinBitrateBps));
+  config_.bitrate_bps = rtc::Optional<int>(rtc::SafeClamp<int>(
+      bits_per_second, kOpusMinBitrateBps, kOpusMaxBitrateBps));
   RTC_DCHECK(config_.IsOk());
   RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps()));
   const auto new_complexity = config_.GetNewComplexity();
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
index 4560958..2402d91 100644
--- a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
@@ -20,6 +20,7 @@
 #endif
 #include "webrtc/base/arraysize.h"
 #include "webrtc/base/random.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/aec3/aec3_fft.h"
 #include "webrtc/modules/audio_processing/aec3/aec_state.h"
 #include "webrtc/modules/audio_processing/aec3/cascaded_biquad_filter.h"
@@ -350,9 +351,8 @@
       fft.Ifft(S, &s);
       std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2, e.begin(),
                      [&](float a, float b) { return a - b * kScale; });
-      std::for_each(e.begin(), e.end(), [](float& a) {
-        a = std::max(std::min(a, 32767.0f), -32768.0f);
-      });
+      std::for_each(e.begin(), e.end(),
+                    [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
       fft.ZeroPaddedFft(e, &E);
 
       gain.Compute(render_buffer, render_signal_analyzer, E,
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc
index ed11959..bc7e600 100644
--- a/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc
+++ b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc
@@ -14,6 +14,7 @@
 #include <algorithm>
 #include <numeric>
 
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/system_wrappers/include/metrics.h"
 
 namespace webrtc {
@@ -273,7 +274,7 @@
   if (negate) {
     new_value = -new_value;
   }
-  return static_cast<int>(std::max(min_value, std::min(max_value, new_value)));
+  return static_cast<int>(rtc::SafeClamp(new_value, min_value, max_value));
 }
 
 }  // namespace aec3
diff --git a/webrtc/modules/audio_processing/aec3/erle_estimator.cc b/webrtc/modules/audio_processing/aec3/erle_estimator.cc
index c139412..7faf22c 100644
--- a/webrtc/modules/audio_processing/aec3/erle_estimator.cc
+++ b/webrtc/modules/audio_processing/aec3/erle_estimator.cc
@@ -12,6 +12,8 @@
 
 #include <algorithm>
 
+#include "webrtc/base/safe_minmax.h"
+
 namespace webrtc {
 
 namespace {
@@ -48,7 +50,7 @@
         if (new_erle > erle_[k]) {
           hold_counters_[k - 1] = 100;
           erle_[k] += 0.1f * (new_erle - erle_[k]);
-          erle_[k] = std::max(kMinErle, std::min(erle_[k], max_erle));
+          erle_[k] = rtc::SafeClamp(erle_[k], kMinErle, max_erle);
         }
       }
     }
diff --git a/webrtc/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc b/webrtc/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
index 2a4d4d6..581856b 100644
--- a/webrtc/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
+++ b/webrtc/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
@@ -15,6 +15,7 @@
 #include <string>
 
 #include "webrtc/base/random.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h"
 #include "webrtc/modules/audio_processing/aec3/aec_state.h"
 #include "webrtc/modules/audio_processing/aec3/render_buffer.h"
@@ -99,9 +100,8 @@
     std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
                    e_main.begin(),
                    [&](float a, float b) { return a - b * kScale; });
-    std::for_each(e_main.begin(), e_main.end(), [](float& a) {
-      a = std::max(std::min(a, 32767.0f), -32768.0f);
-    });
+    std::for_each(e_main.begin(), e_main.end(),
+                  [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
     fft.ZeroPaddedFft(e_main, &E_main);
 
     // Apply the shadow filter.
@@ -110,9 +110,8 @@
     std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
                    e_shadow.begin(),
                    [&](float a, float b) { return a - b * kScale; });
-    std::for_each(e_shadow.begin(), e_shadow.end(), [](float& a) {
-      a = std::max(std::min(a, 32767.0f), -32768.0f);
-    });
+    std::for_each(e_shadow.begin(), e_shadow.end(),
+                  [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
     fft.ZeroPaddedFft(e_shadow, &E_shadow);
 
     // Compute spectra for future use.
diff --git a/webrtc/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc b/webrtc/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
index 82850f8..40bee42 100644
--- a/webrtc/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
+++ b/webrtc/modules/audio_processing/aec3/shadow_filter_update_gain_unittest.cc
@@ -16,9 +16,10 @@
 #include <vector>
 
 #include "webrtc/base/random.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h"
-#include "webrtc/modules/audio_processing/aec3/aec_state.h"
 #include "webrtc/modules/audio_processing/aec3/aec3_common.h"
+#include "webrtc/modules/audio_processing/aec3/aec_state.h"
 #include "webrtc/modules/audio_processing/test/echo_canceller_test_tools.h"
 #include "webrtc/test/gtest.h"
 
@@ -75,9 +76,8 @@
     std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2,
                    e_shadow.begin(),
                    [&](float a, float b) { return a - b * kScale; });
-    std::for_each(e_shadow.begin(), e_shadow.end(), [](float& a) {
-      a = std::max(std::min(a, 32767.0f), -32768.0f);
-    });
+    std::for_each(e_shadow.begin(), e_shadow.end(),
+                  [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
     fft.ZeroPaddedFft(e_shadow, &E_shadow);
 
     shadow_gain.Compute(render_buffer, render_signal_analyzer, E_shadow,
diff --git a/webrtc/modules/audio_processing/aec3/subtractor.cc b/webrtc/modules/audio_processing/aec3/subtractor.cc
index 3897d94..dc3ec06 100644
--- a/webrtc/modules/audio_processing/aec3/subtractor.cc
+++ b/webrtc/modules/audio_processing/aec3/subtractor.cc
@@ -14,6 +14,7 @@
 
 #include "webrtc/base/array_view.h"
 #include "webrtc/base/checks.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
 
 namespace webrtc {
@@ -30,9 +31,8 @@
   constexpr float kScale = 1.0f / kFftLengthBy2;
   std::transform(y.begin(), y.end(), s.begin() + kFftLengthBy2, e->begin(),
                  [&](float a, float b) { return a - b * kScale; });
-  std::for_each(e->begin(), e->end(), [](float& a) {
-    a = std::max(std::min(a, 32767.0f), -32768.0f);
-  });
+  std::for_each(e->begin(), e->end(),
+                [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
   fft.ZeroPaddedFft(*e, E);
 }
 }  // namespace
diff --git a/webrtc/modules/audio_processing/aec3/suppression_filter.cc b/webrtc/modules/audio_processing/aec3/suppression_filter.cc
index b172a1d..1121c74 100644
--- a/webrtc/modules/audio_processing/aec3/suppression_filter.cc
+++ b/webrtc/modules/audio_processing/aec3/suppression_filter.cc
@@ -16,6 +16,7 @@
 #include <functional>
 #include <numeric>
 
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/utility/ooura_fft.h"
 
 namespace webrtc {
@@ -122,7 +123,7 @@
   std::transform((*e)[0].begin(), (*e)[0].end(), e_extended.begin(),
                  (*e)[0].begin(), std::plus<float>());
   std::for_each((*e)[0].begin(), (*e)[0].end(), [](float& x_k) {
-    x_k = std::max(std::min(x_k, 32767.0f), -32768.0f);
+    x_k = rtc::SafeClamp(x_k, -32768.f, 32767.f);
   });
   std::copy(e_extended.begin() + kFftLengthBy2, e_extended.begin() + kFftLength,
             std::begin(e_output_old_[0]));
@@ -154,7 +155,7 @@
     if (e->size() > 2) {
       RTC_DCHECK_EQ(3, e->size());
       std::for_each((*e)[2].begin(), (*e)[2].end(), [&](float& a) {
-        a = std::max(std::min(a * high_bands_gain, 32767.0f), -32768.0f);
+        a = rtc::SafeClamp(a * high_bands_gain, -32768.f, 32767.f);
       });
     }
 
diff --git a/webrtc/modules/audio_processing/agc/agc_manager_direct.cc b/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
index 5d1e7cd..6a19945 100644
--- a/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
+++ b/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
@@ -18,6 +18,7 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/agc/gain_map_internal.h"
 #include "webrtc/modules/audio_processing/gain_control_impl.h"
 #include "webrtc/modules/include/module_common_types.h"
@@ -56,7 +57,7 @@
 const int kSurplusCompressionGain = 6;
 
 int ClampLevel(int mic_level) {
-  return std::min(std::max(kMinMicLevel, mic_level), kMaxMicLevel);
+  return rtc::SafeClamp(mic_level, kMinMicLevel, kMaxMicLevel);
 }
 
 int LevelFromGainError(int gain_error, int level) {
@@ -380,8 +381,9 @@
   rms_error += kMinCompressionGain;
 
   // Handle as much error as possible with the compressor first.
-  int raw_compression = std::max(std::min(rms_error, max_compression_gain_),
-                                 kMinCompressionGain);
+  int raw_compression =
+      rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_);
+
   // Deemphasize the compression gain error. Move halfway between the current
   // target and the newly received target. This serves to soften perceptible
   // intra-talkspurt adjustments, at the cost of some adaptation speed.
@@ -400,9 +402,9 @@
   // Residual error will be handled by adjusting the volume slider. Use the
   // raw rather than deemphasized compression here as we would otherwise
   // shrink the amount of slack the compressor provides.
-  int residual_gain = rms_error - raw_compression;
-  residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange),
-      kMaxResidualGainChange);
+  const int residual_gain =
+      rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange,
+                     kMaxResidualGainChange);
   LOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", "
                << "target_compression=" << target_compression_ << ", "
                << "residual_gain=" << residual_gain;
diff --git a/webrtc/modules/audio_processing/audio_processing_unittest.cc b/webrtc/modules/audio_processing/audio_processing_unittest.cc
index 4d97904..42cf418 100644
--- a/webrtc/modules/audio_processing/audio_processing_unittest.cc
+++ b/webrtc/modules/audio_processing/audio_processing_unittest.cc
@@ -680,15 +680,13 @@
   // limit them w.r.t. AEC delay estimation support.
   const size_t samples_per_ms =
       rtc::SafeMin<size_t>(16u, frame_->samples_per_channel_ / 10);
-  int expected_median = std::min(std::max(delay_ms - system_delay_ms,
-                                          delay_min), delay_max);
-  int expected_median_high = std::min(
-      std::max(expected_median + static_cast<int>(96 / samples_per_ms),
-               delay_min),
+  const int expected_median =
+      rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
+  const int expected_median_high = rtc::SafeClamp<int>(
+      expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
       delay_max);
-  int expected_median_low = std::min(
-      std::max(expected_median - static_cast<int>(96 / samples_per_ms),
-               delay_min),
+  const int expected_median_low = rtc::SafeClamp<int>(
+      expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
       delay_max);
   // Verify delay metrics.
   int median;
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
index 7ff2cf4..f5414aa 100644
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
+++ b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
@@ -18,6 +18,7 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/common_audio/include/audio_util.h"
 #include "webrtc/common_audio/window_generator.h"
 
@@ -287,23 +288,23 @@
   }
 
   for (size_t i = 1; i <= bank_size_; ++i) {
-    static const size_t kOne = 1;  // Avoids repeated static_cast<>s below.
-    size_t lll =
-        static_cast<size_t>(round(center_freqs_[std::max(kOne, i - lf) - 1] *
-                                  num_freqs / (0.5f * sample_rate_hz_)));
-    size_t ll = static_cast<size_t>(round(center_freqs_[std::max(kOne, i) - 1] *
-                                   num_freqs / (0.5f * sample_rate_hz_)));
-    lll = std::min(num_freqs, std::max(lll, kOne)) - 1;
-    ll = std::min(num_freqs, std::max(ll, kOne)) - 1;
+    size_t lll = static_cast<size_t>(
+        round(center_freqs_[rtc::SafeMax<size_t>(1, i - lf) - 1] * num_freqs /
+              (0.5f * sample_rate_hz_)));
+    size_t ll = static_cast<size_t>(
+        round(center_freqs_[rtc::SafeMax<size_t>(1, i) - 1] * num_freqs /
+              (0.5f * sample_rate_hz_)));
+    lll = rtc::SafeClamp<size_t>(lll, 1, num_freqs) - 1;
+    ll = rtc::SafeClamp<size_t>(ll, 1, num_freqs) - 1;
 
     size_t rrr = static_cast<size_t>(
-        round(center_freqs_[std::min(bank_size_, i + rf) - 1] * num_freqs /
-              (0.5f * sample_rate_hz_)));
+        round(center_freqs_[rtc::SafeMin<size_t>(bank_size_, i + rf) - 1] *
+              num_freqs / (0.5f * sample_rate_hz_)));
     size_t rr = static_cast<size_t>(
-        round(center_freqs_[std::min(bank_size_, i + 1) - 1] * num_freqs /
-              (0.5f * sample_rate_hz_)));
-    rrr = std::min(num_freqs, std::max(rrr, kOne)) - 1;
-    rr = std::min(num_freqs, std::max(rr, kOne)) - 1;
+        round(center_freqs_[rtc::SafeMin<size_t>(bank_size_, i + 1) - 1] *
+              num_freqs / (0.5f * sample_rate_hz_)));
+    rrr = rtc::SafeClamp<size_t>(rrr, 1, num_freqs) - 1;
+    rr = rtc::SafeClamp<size_t>(rr, 1, num_freqs) - 1;
 
     float step = ll == lll ? 0.f : 1.f / (ll - lll);
     float element = 0.f;
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
index fa8d170..deaeb27 100644
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
+++ b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
@@ -16,6 +16,8 @@
 #include <algorithm>
 #include <limits>
 
+#include "webrtc/base/safe_minmax.h"
+
 namespace webrtc {
 
 namespace intelligibility {
@@ -28,9 +30,9 @@
 // Return |current| changed towards |target|, with the relative change being at
 // most |limit|.
 float UpdateFactor(float target, float current, float limit) {
-  float gain = target / (current + std::numeric_limits<float>::epsilon());
-  gain = std::min(std::max(gain, 1.f - limit), 1.f + limit);
-  return std::min(std::max(current * gain, kMinFactor), kMaxFactor);;
+  const float gain = target / (current + std::numeric_limits<float>::epsilon());
+  const float clamped_gain = rtc::SafeClamp(gain, 1 - limit, 1 + limit);
+  return rtc::SafeClamp(current * clamped_gain, kMinFactor, kMaxFactor);
 }
 
 }  // namespace
diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
index d903cf9..4b9343c 100644
--- a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
+++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
@@ -62,11 +62,11 @@
   // Estimate how often we can send RTCP if we allocate up to 5% of bandwidth
   // to feedback.
   static const int kRtcpSize = 80;
-  int64_t interval = static_cast<int64_t>(
+  const int64_t interval = static_cast<int64_t>(
       kRtcpSize * 8.0 * 1000.0 / (0.05 * current_bitrate_bps_) + 0.5);
   const int64_t kMinFeedbackIntervalMs = 200;
-  return std::min(std::max(interval, kMinFeedbackIntervalMs),
-                  kMaxFeedbackIntervalMs);
+  return rtc::SafeClamp(interval, kMinFeedbackIntervalMs,
+                        kMaxFeedbackIntervalMs);
 }
 
 bool AimdRateControl::TimeToReduceFurther(int64_t time_now,
diff --git a/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc b/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc
index 399daf0..6b2b518 100644
--- a/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc
+++ b/webrtc/modules/remote_bitrate_estimator/overuse_detector.cc
@@ -19,6 +19,7 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
@@ -144,11 +145,7 @@
   int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
   threshold_ +=
       k * (fabs(modified_offset) - threshold_) * time_delta_ms;
-
-  const double kMinThreshold = 6;
-  const double kMaxThreshold = 600;
-  threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);
-
+  threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);
   last_update_ms_ = now_ms;
 }
 
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
index 3700fc4..35bc667 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
@@ -15,10 +15,11 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
-#include "webrtc/system_wrappers/include/clock.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/pacing/packet_router.h"
-#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "webrtc/system_wrappers/include/clock.h"
 
 namespace webrtc {
 
@@ -104,8 +105,9 @@
 
   // Let TWCC reports occupy 5% of total bandwidth.
   rtc::CritScope cs(&lock_);
-  send_interval_ms_ = static_cast<int>(0.5 + kTwccReportSize * 8.0 * 1000.0 /
-      (std::max(std::min(0.05 * bitrate_bps, kMaxTwccRate), kMinTwccRate)));
+  send_interval_ms_ = static_cast<int>(
+      0.5 + kTwccReportSize * 8.0 * 1000.0 /
+                rtc::SafeClamp(0.05 * bitrate_bps, kMinTwccRate, kMaxTwccRate));
 }
 
 void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
index 15e759b..1361277 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
@@ -15,6 +15,7 @@
 #include <sstream>
 
 #include "webrtc/base/constructormagic.h"
+#include "webrtc/base/safe_minmax.h"
 
 namespace webrtc {
 namespace testing {
@@ -406,8 +407,8 @@
 inline int64_t TruncatedNSigmaGaussian(Random* const random,
                                        int64_t mean,
                                        int64_t std_dev) {
-  int64_t gaussian_random = random->Gaussian(mean, std_dev);
-  return std::max(std::min(gaussian_random, kN * std_dev), -kN * std_dev);
+  const int64_t gaussian_random = random->Gaussian(mean, std_dev);
+  return rtc::SafeClamp(gaussian_random, -kN * std_dev, kN * std_dev);
 }
 }
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 3cac419..1bdb804 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -17,8 +17,9 @@
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/rate_limiter.h"
-#include "webrtc/base/trace_event.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/base/timeutils.h"
+#include "webrtc/base/trace_event.h"
 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
@@ -467,16 +468,16 @@
 
   if (audio_configured_) {
     // Allow smaller padding packets for audio.
-    padding_bytes_in_packet =
-        std::min(std::max(bytes, kMinAudioPaddingLength), max_payload_size);
-    if (padding_bytes_in_packet > kMaxPaddingLength)
-      padding_bytes_in_packet = kMaxPaddingLength;
+    padding_bytes_in_packet = rtc::SafeClamp<size_t>(
+        bytes, kMinAudioPaddingLength,
+        rtc::SafeMin(max_payload_size, kMaxPaddingLength));
   } else {
     // Always send full padding packets. This is accounted for by the
     // RtpPacketSender, which will make sure we don't send too much padding even
     // if a single packet is larger than requested.
     // We do this to avoid frequently sending small packets on higher bitrates.
-    padding_bytes_in_packet = std::min(max_payload_size, kMaxPaddingLength);
+    padding_bytes_in_packet =
+        rtc::SafeMin<size_t>(max_payload_size, kMaxPaddingLength);
   }
   size_t bytes_sent = 0;
   while (bytes_sent < bytes) {
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc
index bf54924..e657125 100644
--- a/webrtc/p2p/base/port.cc
+++ b/webrtc/p2p/base/port.cc
@@ -21,6 +21,7 @@
 #include "webrtc/base/messagedigest.h"
 #include "webrtc/base/network.h"
 #include "webrtc/base/ptr_util.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/base/stringencode.h"
 #include "webrtc/base/stringutils.h"
 #include "webrtc/p2p/base/common.h"
@@ -69,7 +70,7 @@
 
 // Computes our estimate of the RTT given the current estimate.
 inline int ConservativeRTTEstimate(int rtt) {
-  return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
+  return rtc::SafeClamp(2 * rtt, MINIMUM_RTT, MAXIMUM_RTT);
 }
 
 // Weighting of the old rtt value to new data.
diff --git a/webrtc/p2p/base/pseudotcp.cc b/webrtc/p2p/base/pseudotcp.cc
index 8257b92..d93f49e 100644
--- a/webrtc/p2p/base/pseudotcp.cc
+++ b/webrtc/p2p/base/pseudotcp.cc
@@ -23,6 +23,7 @@
 #include "webrtc/base/byteorder.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/base/socket.h"
 #include "webrtc/base/stringutils.h"
 #include "webrtc/base/timeutils.h"
@@ -155,10 +156,6 @@
   return rtc::NetworkToHost16(*static_cast<const uint16_t*>(buf));
 }
 
-uint32_t bound(uint32_t lower, uint32_t middle, uint32_t upper) {
-  return std::min(std::max(lower, middle), upper);
-}
-
 //////////////////////////////////////////////////////////////////////
 // Debugging Statistics
 //////////////////////////////////////////////////////////////////////
@@ -725,9 +722,8 @@
           m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
           m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
         }
-        m_rx_rto =
-            bound(MIN_RTO, m_rx_srtt + std::max<uint32_t>(1, 4 * m_rx_rttvar),
-                  MAX_RTO);
+        m_rx_rto = rtc::SafeClamp(m_rx_srtt + rtc::SafeMax(1, 4 * m_rx_rttvar),
+                                  MIN_RTO, MAX_RTO);
 #if _DEBUGMSG >= _DBG_VERBOSE
         LOG(LS_INFO) << "rtt: " << rtt
                      << "  srtt: " << m_rx_srtt
diff --git a/webrtc/tools/agc/activity_metric.cc b/webrtc/tools/agc/activity_metric.cc
index 599777c..9715d62 100644
--- a/webrtc/tools/agc/activity_metric.cc
+++ b/webrtc/tools/agc/activity_metric.cc
@@ -17,6 +17,7 @@
 #include <memory>
 
 #include "webrtc/base/flags.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/modules/audio_processing/agc/agc.h"
 #include "webrtc/modules/audio_processing/agc/loudness_histogram.h"
 #include "webrtc/modules/audio_processing/agc/utility.h"
@@ -121,9 +122,7 @@
       for (size_t n = 0; n < features.num_frames; n++) {
         double p_active = p[n] * video_vad_[n];
         double p_passive = (1 - p[n]) * (1 - video_vad_[n]);
-        p[n]  = p_active / (p_active + p_passive);
-        // Limit probabilities.
-        p[n] = std::min(std::max(p[n], 0.01), 0.99);
+        p[n] = rtc::SafeClamp(p_active / (p_active + p_passive), 0.01, 0.99);
       }
       if (vad_->VoicingProbability(features, p) < 0)
         return -1;
diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc
index 46bcef9..4a0b3cc 100644
--- a/webrtc/voice_engine/channel_proxy.cc
+++ b/webrtc/voice_engine/channel_proxy.cc
@@ -15,6 +15,7 @@
 #include "webrtc/api/call/audio_sink.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
+#include "webrtc/base/safe_minmax.h"
 #include "webrtc/call/rtp_transport_controller_send_interface.h"
 #include "webrtc/voice_engine/channel.h"
 
@@ -290,7 +291,7 @@
   RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread());
   // Limit to range accepted by both VoE and ACM, so we're at least getting as
   // close as possible, instead of failing.
-  delay_ms = std::max(0, std::min(delay_ms, 10000));
+  delay_ms = rtc::SafeClamp(delay_ms, 0, 10000);
   int error = channel()->SetMinimumPlayoutDelay(delay_ms);
   if (0 != error) {
     LOG(LS_WARNING) << "Error setting minimum playout delay.";