Add ClampedNumeric templates

Add template classes for clamped (not sticky) saturating math.

BUG=672489

Review-Url: https://codereview.chromium.org/2945433003
Cr-Commit-Position: refs/heads/master@{#484005}


CrOS-Libchrome-Original-Commit: b180f39aa6a2edc68a5c0e2308aabe639ec029f8
diff --git a/base/numerics/README.md b/base/numerics/README.md
new file mode 100644
index 0000000..d89df9e
--- /dev/null
+++ b/base/numerics/README.md
@@ -0,0 +1,260 @@
+# `base/numerics`
+
+This directory contains templates providing well-defined semantics for safely
+handling a variety of numeric operations, including most common arithmetic
+operations and conversions.
+
+The public API is broken out into the following header files:
+
+*   `checked_math.h` contains the `CheckedNumeric` template class and helper
+    functions for performing arithmetic and conversion operations that detect
+    errors and boundary conditions (e.g. overflow, truncation, etc.).
+*   `clamped_math.h` contains the `ClampedNumeric` template class and
+    helper functions for performing fast, clamped (i.e. non-sticky saturating)
+    arithmetic operations and conversions.
+*   `safe_conversions.h` contains the `StrictNumeric` template class and
+    a collection of custom casting templates and helper functions for safely
+    converting between a range of numeric types.
+*   `safe_math.h` includes all of the previously mentioned headers.
+
+*** aside
+**Note:** The `Numeric` template types implicitly convert from C numeric types
+and `Numeric` templates that are convertable to an underlying C numeric type.
+The conversion priority for `Numeric` type coercions is:
+
+*   `StrictNumeric` coerces to `ClampedNumeric` and `CheckedNumeric`
+*   `ClampedNumeric` coerces to `CheckedNumeric` 
+***
+
+[TOC]
+
+## Conversion functions and `StrictNumeric<>` in `safe_conversions.h`
+
+This header includes a collection of helper `constexpr` templates for safely
+performing a range of conversions, assignments, and tests.
+
+### Safe casting templates
+
+*   `as_signed()` - Returns the supplied integral value as a signed type of
+    the same width.
+*   `as_unsigned()` - Returns the supplied integral value as an unsigned type
+    of the same width.
+*   `checked_cast<>()` - Analogous to `static_cast<>` for numeric types, except
+    that by default it will trigger a crash on an out-of-bounds conversion (e.g.
+    overflow, underflow, NaN to integral) or a compile error if the conversion
+    error can be detected at compile time. The crash handler can be overridden
+    to perform a behavior other than crashing.
+*   `saturated_cast<>()` - Analogous to `static_cast` for numeric types, except
+    that it returns a saturated result when the specified numeric conversion
+    would otherwise overflow or underflow. An NaN source returns 0 by
+    default, but can be overridden to return a different result.
+*   `strict_cast<>()` - Analogous to `static_cast` for numeric types, except
+    this causes a compile failure if the destination type is not large
+    enough to contain any value in the source type. It performs no runtime
+    checking and thus introduces no runtime overhead.
+
+### Other helper and conversion functions
+
+*   `IsValueInRangeForNumericType<>()` - A convenience function that returns
+    true if the type supplied to the template parameter can represent the value
+    passed as an argument to the function.
+*   `IsValueNegative()` - A convenience function that will accept any
+    arithmetic type as an argument and will return whether the value is less
+    than zero. Unsigned types always return false.
+*   `SafeUnsignedAbs()` - Returns the absolute value of the supplied integer
+    parameter as an unsigned result (thus avoiding an overflow if the value
+    is the signed, two's complement minimum).
+
+### `StrictNumeric<>`
+
+`StrictNumeric<>` is a wrapper type that performs assignments and copies via
+the `strict_cast` template, and can perform valid arithmetic comparisons
+across any range of arithmetic types. `StrictNumeric` is the return type for
+values extracted from a `CheckedNumeric` class instance. The raw numeric value
+is extracted via `static_cast` to the underlying type or any type with
+sufficient range to represent the underlying type.
+
+*   `MakeStrictNum()` - Creates a new `StrictNumeric` from the underlying type
+    of the supplied arithmetic or StrictNumeric type.
+*   `SizeT` - Alias for `StrictNumeric<size_t>`.
+
+## `CheckedNumeric<>` in `checked_math.h`
+
+`CheckedNumeric<>` implements all the logic and operators for detecting integer
+boundary conditions such as overflow, underflow, and invalid conversions.
+The `CheckedNumeric` type implicitly converts from floating point and integer
+data types, and contains overloads for basic arithmetic operations (i.e.: `+`,
+`-`, `*`, `/` for all types and `%`, `<<`, `>>`, `&`, `|`, `^` for integers).
+Type promotions are a slightly modified version of the [standard C/C++ numeric
+promotions
+](http://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions)
+with the two differences being that there is no default promotion to int
+and bitwise logical operations always return an unsigned of the wider type.
+
+### Members
+
+The unary negation, increment, and decrement operators are supported, along
+with the following unary arithmetic methods, which return a new
+`CheckedNumeric` as a result of the operation:
+
+*   `Abs()` - Absolute value.
+*   `UnsignedAbs()` - Absolute value as an equal-width unsigned underlying type
+    (valid for only integral types).
+*   `Max()` - Returns whichever is greater of the current instance or argument.
+    The underlying return type is whichever has the greatest magnitude.
+*   `Min()` - Returns whichever is lowest of the current instance or argument.
+    The underlying return type is whichever has can represent the lowest
+    number in the smallest width (e.g. int8_t over unsigned, int over
+    int8_t, and float over int).
+
+The following are for converting `CheckedNumeric` instances:
+
+*   `type` - The underlying numeric type.
+*   `AssignIfValid()` - Assigns the underlying value to the supplied
+    destination pointer if the value is currently valid and within the
+    range supported by the destination type. Returns true on success.
+*   `Cast<>()` - Instance method returning a `CheckedNumeric` derived from
+    casting the current instance to a `CheckedNumeric` of the supplied
+    destination type.
+
+*** aside
+The following member functions return a `StrictNumeric`, which is valid for
+comparison and assignment operations, but will trigger a compile failure on
+attempts to assign to a type of insufficient range. The underlying value can
+be extracted by an explicit `static_cast` to the underlying type or any type
+with sufficient range to represent the underlying type.
+***
+
+*   `IsValid()` - Returns true if the underlying numeric value is valid (i.e.
+    has not wrapped or saturated and is not the result of an invalid
+    conversion).
+*   `ValueOrDie()` - Returns the underlying value. If the state is not valid
+    this call will trigger a crash by default (but may be overridden by
+    supplying an alternate handler to the template).
+*   `ValueOrDefault()` - Returns the current value, or the supplied default if
+    the state is not valid (but will not crash).
+
+**Comparison operators are explicitly not provided** for `CheckedNumeric`
+types because they could result in a crash if the type is not in a valid state.
+Patterns like the following should be used instead:
+
+```cpp
+CheckedNumeric<size_t> checked_size = untrusted_input_value;
+checked_size += HEADER LENGTH;
+if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) {
+  \\ Do stuff on success...
+} else {
+  \\ Handle an error...
+}
+```
+
+### Non-member helper functions
+
+The following variadic convenience functions, which accept standard arithmetic
+or `CheckedNumeric` types, perform arithmetic operations, and return a
+`CheckedNumeric` result. The supported functions are:
+
+*   `CheckAdd()` - Addition.
+*   `CheckSub()` - Subtraction.
+*   `CheckMul()` - Multiplication.
+*   `CheckDiv()` - Division.
+*   `CheckMod()` - Modulus (integer only).
+*   `CheckLsh()` - Left integer shift (integer only).
+*   `CheckRsh()` - Right integer shift (integer only).
+*   `CheckAnd()` - Bitwise AND (integer only with unsigned result).
+*   `CheckOr()`  - Bitwise OR (integer only with unsigned result).
+*   `CheckXor()` - Bitwise XOR (integer only with unsigned result).
+*   `CheckMax()` - Maximum of supplied arguments.
+*   `CheckMin()` - Minimum of supplied arguments.
+
+The following wrapper functions can be used to avoid the template
+disambiguator syntax when converting a destination type.
+
+*   `IsValidForType<>()` in place of: `a.template IsValid<>()`
+*   `ValueOrDieForType<>()` in place of: `a.template ValueOrDie<>()`
+*   `ValueOrDefaultForType<>()` in place of: `a.template ValueOrDefault<>()`
+
+The following general utility methods is are useful for converting from
+arithmetic types to `CheckedNumeric` types:
+
+*   `MakeCheckedNum()` - Creates a new `CheckedNumeric` from the underlying type
+    of the supplied arithmetic or directly convertible type.
+
+## `ClampedNumeric<>` in `clamped_math.h`
+
+`ClampedNumeric<>` implements all the logic and operators for clamped
+(non-sticky saturating) arithmetic operations and conversions. The
+`ClampedNumeric` type implicitly converts back and forth between floating point
+and integer data types, saturating on assignment as appropriate. It contains
+overloads for basic arithmetic operations (i.e.: `+`, `-`, `*`, `/` for
+all types and `%`, `<<`, `>>`, `&`, `|`, `^` for integers) along with comparison
+operators for arithmetic types of any size. Type promotions are a slightly
+modified version of the [standard C/C++ numeric promotions
+](http://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions)
+with the two differences being that there is no default promotion to int and
+bitwise logical operations always return an unsigned of the wider type.
+
+*** aside
+Most arithmetic operations saturate normally, to the numeric limit in the
+direction of the sign. The potentially unusual cases are:
+
+*   **Division:** Division by zero returns the saturated limit in the direction
+    of sign of the dividend (first argument). The one exception is 0/0, which
+	returns zero (although logically is NaN).
+*   **Modulus:** Division by zero returns the dividend (first argument).
+*   **Left shift:** Non-zero values saturate in the direction of the signed
+    limit (max/min), even for shifts larger than the bit width. 0 shifted any
+    amount results in 0.
+*   **Right shift:** Negative values saturate to -1. Positive or 0 saturates
+    to 0.
+*   **Bitwise operations:** No saturation; bit pattern is identical to
+    non-saturated bitwise operations.
+***
+
+### Members
+
+The unary negation, increment, and decrement operators are supported, along
+with the following unary arithmetic methods, which return a new
+`ClampedNumeric` as a result of the operation:
+
+*   `Abs()` - Absolute value.
+*   `UnsignedAbs()` - Absolute value as an equal-width unsigned underlying type
+    (valid for only integral types).
+*   `Max()` - Returns whichever is greater of the current instance or argument.
+    The underlying return type is whichever has the greatest magnitude.
+*   `Min()` - Returns whichever is lowest of the current instance or argument.
+    The underlying return type is whichever has can represent the lowest
+    number in the smallest width (e.g. int8_t over unsigned, int over
+    int8_t, and float over int).
+
+The following are for converting `ClampedNumeric` instances:
+
+*   `type` - The underlying numeric type.
+*   `Cast<>()` - Instance method returning a `ClampedNumeric` derived from
+    casting the current instance to a `ClampedNumeric` of the supplied
+    destination type.
+
+### Non-member helper functions
+
+The following variadic convenience functions, which accept standard arithmetic
+or `ClampedNumeric` types, perform arithmetic operations, and return a
+`ClampedNumeric` result. The supported functions are:
+
+*   `ClampAdd()` - Addition.
+*   `ClampSub()` - Subtraction.
+*   `ClampMul()` - Multiplication.
+*   `ClampDiv()` - Division.
+*   `ClampMod()` - Modulus (integer only).
+*   `ClampLsh()` - Left integer shift (integer only).
+*   `ClampRsh()` - Right integer shift (integer only).
+*   `ClampAnd()` - Bitwise AND (integer only with unsigned result).
+*   `ClampOr()`  - Bitwise OR (integer only with unsigned result).
+*   `ClampXor()` - Bitwise XOR (integer only with unsigned result).
+*   `ClampMax()` - Maximum of supplied arguments.
+*   `ClampMin()` - Minimum of supplied arguments.
+
+The following is a general utility method that is useful for converting
+to a `ClampedNumeric` type:
+
+*   `MakeClampedNum()` - Creates a new `ClampedNumeric` from the underlying type
+    of the supplied arithmetic or directly convertible type.
diff --git a/base/numerics/checked_math.h b/base/numerics/checked_math.h
index 00a88e3..1f8ea9d 100644
--- a/base/numerics/checked_math.h
+++ b/base/numerics/checked_math.h
@@ -15,82 +15,6 @@
 namespace base {
 namespace internal {
 
-// CheckedNumeric<> implements all the logic and operators for detecting integer
-// boundary conditions such as overflow, underflow, and invalid conversions.
-// The CheckedNumeric type implicitly converts from floating point and integer
-// data types, and contains overloads for basic arithmetic operations (i.e.: +,
-// -, *, / for all types and %, <<, >>, &, |, ^ for integers). Type promotions
-// are a slightly modified version of the standard C arithmetic rules with the
-// two differences being that there is no default promotion to int and bitwise
-// logical operations always return an unsigned of the wider type.
-//
-// You may also use one of the variadic convenience functions, which accept
-// standard arithmetic or CheckedNumeric types, perform arithmetic operations,
-// and return a CheckedNumeric result. The supported functions are:
-//  CheckAdd() - Addition.
-//  CheckSub() - Subtraction.
-//  CheckMul() - Multiplication.
-//  CheckDiv() - Division.
-//  CheckMod() - Modulous (integer only).
-//  CheckLsh() - Left integer shift (integer only).
-//  CheckRsh() - Right integer shift (integer only).
-//  CheckAnd() - Bitwise AND (integer only with unsigned result).
-//  CheckOr()  - Bitwise OR (integer only with unsigned result).
-//  CheckXor() - Bitwise XOR (integer only with unsigned result).
-//  CheckMax() - Maximum of supplied arguments.
-//  CheckMin() - Minimum of supplied arguments.
-//
-// The unary negation, increment, and decrement operators are supported, along
-// with the following unary arithmetic methods, which return a new
-// CheckedNumeric as a result of the operation:
-//  Abs() - Absolute value.
-//  UnsignedAbs() - Absolute value as an equal-width unsigned underlying type
-//          (valid for only integral types).
-//  Max() - Returns whichever is greater of the current instance or argument.
-//          The underlying return type is whichever has the greatest magnitude.
-//  Min() - Returns whichever is lowest of the current instance or argument.
-//          The underlying return type is whichever has can represent the lowest
-//          number in the smallest width (e.g. int8_t over unsigned, int over
-//          int8_t, and float over int).
-//
-// The following methods convert from CheckedNumeric to standard numeric values:
-//  AssignIfValid() - Assigns the underlying value to the supplied destination
-//          pointer if the value is currently valid and within the range
-//          supported by the destination type. Returns true on success.
-//  ****************************************************************************
-//  *  WARNING: All of the following functions return a StrictNumeric, which   *
-//  *  is valid for comparison and assignment operations, but will trigger a   *
-//  *  compile failure on attempts to assign to a type of insufficient range.  *
-//  ****************************************************************************
-//  IsValid() - Returns true if the underlying numeric value is valid (i.e. has
-//          has not wrapped and is not the result of an invalid conversion).
-//  ValueOrDie() - Returns the underlying value. If the state is not valid this
-//          call will crash on a CHECK.
-//  ValueOrDefault() - Returns the current value, or the supplied default if the
-//          state is not valid (will not trigger a CHECK).
-//
-// The following wrapper functions can be used to avoid the template
-// disambiguator syntax when converting a destination type.
-//   IsValidForType<>() in place of: a.template IsValid<Dst>()
-//   ValueOrDieForType<>() in place of: a.template ValueOrDie()
-//   ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default)
-//
-// The following are general utility methods that are useful for converting
-// between arithmetic types and CheckedNumeric types:
-//  CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric
-//          derived from casting the current instance to a CheckedNumeric of
-//          the supplied destination type.
-//  MakeCheckedNum() - Creates a new CheckedNumeric from the underlying type of
-//          the supplied arithmetic, CheckedNumeric, or StrictNumeric type.
-//
-// Comparison operations are explicitly not supported because they could result
-// in a crash on an unexpected CHECK condition. You should use patterns like the
-// following for comparisons:
-//   CheckedNumeric<size_t> checked_size = untrusted_input_value;
-//   checked_size += HEADER LENGTH;
-//   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
-//     Do stuff...
-
 template <typename T>
 class CheckedNumeric {
   static_assert(std::is_arithmetic<T>::value,
@@ -377,8 +301,8 @@
 template <template <typename, typename, typename> class M,
           typename L,
           typename R>
-CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs,
-                                                              const R rhs) {
+CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp(const L lhs,
+                                                                const R rhs) {
   using Math = typename MathWrapper<M, L, R>::math;
   return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
                                                                         rhs);
@@ -390,10 +314,10 @@
           typename R,
           typename... Args>
 CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
-ChkMathOp(const L lhs, const R rhs, const Args... args) {
-  auto tmp = ChkMathOp<M>(lhs, rhs);
-  return tmp.IsValid() ? ChkMathOp<M>(tmp, args...)
-                       : decltype(ChkMathOp<M>(tmp, args...))(tmp);
+CheckMathOp(const L lhs, const R rhs, const Args... args) {
+  auto tmp = CheckMathOp<M>(lhs, rhs);
+  return tmp.IsValid() ? CheckMathOp<M>(tmp, args...)
+                       : decltype(CheckMathOp<M>(tmp, args...))(tmp);
 }
 
 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=)
diff --git a/base/numerics/checked_math_impl.h b/base/numerics/checked_math_impl.h
index 0492d1d..bf3a307 100644
--- a/base/numerics/checked_math_impl.h
+++ b/base/numerics/checked_math_impl.h
@@ -182,17 +182,19 @@
       return !__builtin_mul_overflow(x, y, result);
 #endif
     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+    // Verify the destination type can hold the result (always true for 0).
+    if (!(IsValueInRangeForNumericType<Promotion>(x) &&
+          IsValueInRangeForNumericType<Promotion>(y)) &&
+        x && y) {
+      return false;
+    }
     Promotion presult;
-    // Fail if either operand is out of range for the promoted type.
-    // TODO(jschuh): This could be made to work for a broader range of values.
-    bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
-                    IsValueInRangeForNumericType<Promotion>(y);
-
+    bool is_valid = true;
     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
       presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
     } else {
-      is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
-                                 static_cast<Promotion>(y), &presult);
+      is_valid = CheckedMulImpl(static_cast<Promotion>(x),
+                                static_cast<Promotion>(y), &presult);
     }
     *result = static_cast<V>(presult);
     return is_valid && IsValueInRangeForNumericType<V>(presult);
@@ -242,7 +244,7 @@
 template <typename T>
 bool CheckedModImpl(T x, T y, T* result) {
   static_assert(std::is_integral<T>::value, "Type must be integral");
-  if (y > 0) {
+  if (y) {
     *result = static_cast<T>(x % y);
     return true;
   }
@@ -283,15 +285,15 @@
   using result_type = T;
   template <typename V>
   static bool Do(T x, U shift, V* result) {
-    using ShiftType = typename std::make_unsigned<T>::type;
-    static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value;
-    const ShiftType real_shift = static_cast<ShiftType>(shift);
     // Signed shift is not legal on negative values.
-    if (!IsValueNegative(x) && real_shift < kBitWidth) {
+    if (!IsValueNegative(x) &&
+        as_unsigned(shift) < IntegerBitsPlusSign<T>::value) {
       // Just use a multiplication because it's easy.
       // TODO(jschuh): This could probably be made more efficient.
-      if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
-        return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result);
+      if (!std::is_signed<T>::value ||
+          as_unsigned(shift) < std::numeric_limits<T>::digits)
+        return CheckedMulOp<T, T>::Do(x, T(1) << shift, result);
+      *result = 0;
       return !x;  // Special case zero for a full width signed shift.
     }
     return false;
@@ -313,8 +315,7 @@
   template <typename V>
   static bool Do(T x, U shift, V* result) {
     // Use the type conversion push negative values out of range.
-    using ShiftType = typename std::make_unsigned<T>::type;
-    if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
+    if (as_unsigned(shift) < IntegerBitsPlusSign<T>::value) {
       T tmp = x >> shift;
       *result = static_cast<V>(tmp);
       return IsValueInRangeForNumericType<V>(tmp);
diff --git a/base/numerics/clamped_math.h b/base/numerics/clamped_math.h
new file mode 100644
index 0000000..d2c4f29
--- /dev/null
+++ b/base/numerics/clamped_math.h
@@ -0,0 +1,266 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CLAMPED_MATH_H_
+#define BASE_NUMERICS_CLAMPED_MATH_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/clamped_math_impl.h"
+
+namespace base {
+namespace internal {
+
+template <typename T>
+class ClampedNumeric {
+  static_assert(std::is_arithmetic<T>::value,
+                "ClampedNumeric<T>: T must be a numeric type.");
+
+ public:
+  using type = T;
+
+  constexpr ClampedNumeric() : value_(0) {}
+
+  // Copy constructor.
+  template <typename Src>
+  constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs)
+      : value_(saturated_cast<T>(rhs.value_)) {}
+
+  template <typename Src>
+  friend class ClampedNumeric;
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to ClampedNumerics to make them easier to use.
+  template <typename Src>
+  constexpr ClampedNumeric(Src value)  // NOLINT(runtime/explicit)
+      : value_(saturated_cast<T>(value)) {
+    static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+  }
+
+  // This is not an explicit constructor because we want a seamless conversion
+  // from StrictNumeric types.
+  template <typename Src>
+  constexpr ClampedNumeric(
+      StrictNumeric<Src> value)  // NOLINT(runtime/explicit)
+      : value_(saturated_cast<T>(static_cast<Src>(value))) {}
+
+  // Returns a ClampedNumeric of the specified type, cast from the current
+  // ClampedNumeric, and saturated to the destination type.
+  template <typename Dst>
+  constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
+    return *this;
+  }
+
+  // Prototypes for the supported arithmetic operator overloads.
+  template <typename Src>
+  ClampedNumeric& operator+=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator-=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator*=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator/=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator%=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator<<=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator>>=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator&=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator|=(const Src rhs);
+  template <typename Src>
+  ClampedNumeric& operator^=(const Src rhs);
+
+  constexpr ClampedNumeric operator-() const {
+    return ClampedNumeric<T>(
+        // The negation of two's complement int min is int min, so that's the
+        // only overflow case we have to check for.
+        std::is_signed<T>::value
+            ? ((std::is_floating_point<T>::value ||
+                NegateWrapper(value_) != std::numeric_limits<T>::lowest())
+                   ? NegateWrapper(value_)
+                   : std::numeric_limits<T>::max())
+            : T(0));  // Clamped unsigned negation is always zero.
+  }
+
+  constexpr ClampedNumeric operator~() const {
+    return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
+  }
+
+  constexpr ClampedNumeric Abs() const {
+    return ClampedNumeric<T>(
+        // The negation of two's complement int min is int min, so that's the
+        // only overflow case we have to check for.
+        (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
+         AbsWrapper(value_) != std::numeric_limits<T>::lowest())
+            ? AbsWrapper(value_)
+            : std::numeric_limits<T>::max());
+  }
+
+  template <typename U>
+  constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(
+      const U rhs) const {
+    using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
+    return ClampedNumeric<result_type>(
+        ClampedMaxOp<T, U>(value_, Wrapper<U>::value(rhs)));
+  }
+
+  template <typename U>
+  constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(
+      const U rhs) const {
+    using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
+    return ClampedNumeric<result_type>(
+        ClampedMinOp<T, U>(value_, Wrapper<U>::value(rhs)));
+  }
+
+  // This function is available only for integral types. It returns an unsigned
+  // integer of the same width as the source type, containing the absolute value
+  // of the source, and properly handling signed min.
+  constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>
+  UnsignedAbs() const {
+    return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+        SafeUnsignedAbs(value_));
+  }
+
+  ClampedNumeric& operator++() {
+    *this += 1;
+    return *this;
+  }
+
+  ClampedNumeric operator++(int) {
+    ClampedNumeric value = *this;
+    *this += 1;
+    return value;
+  }
+
+  ClampedNumeric& operator--() {
+    *this -= 1;
+    return *this;
+  }
+
+  ClampedNumeric operator--(int) {
+    ClampedNumeric value = *this;
+    *this -= 1;
+    return value;
+  }
+
+  // These perform the actual math operations on the ClampedNumerics.
+  // Binary arithmetic operations.
+  template <template <typename, typename, typename> class M,
+            typename L,
+            typename R>
+  static ClampedNumeric MathOp(const L lhs, const R rhs) {
+    using Math = typename MathWrapper<M, L, R>::math;
+    return ClampedNumeric<T>(
+        Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
+  }
+
+  // Assignment arithmetic operations.
+  template <template <typename, typename, typename> class M, typename R>
+  ClampedNumeric& MathOp(const R rhs) {
+    using Math = typename MathWrapper<M, T, R>::math;
+    *this =
+        ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
+    return *this;
+  }
+
+  template <typename Dst>
+  constexpr operator Dst() const {
+    return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(
+        value_);
+  }
+
+ private:
+  T value_;
+
+  // These wrappers allow us to handle state the same way for both
+  // ClampedNumeric and POD arithmetic types.
+  template <typename Src>
+  struct Wrapper {
+    static constexpr Src value(Src value) {
+      return static_cast<typename UnderlyingType<Src>::type>(value);
+    }
+  };
+};
+
+// Convience wrapper to return a new ClampedNumeric from the provided arithmetic
+// or ClampedNumericType.
+template <typename T>
+constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
+    const T value) {
+  return value;
+}
+
+// Overload the ostream output operator to make logging work nicely.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) {
+  os << static_cast<T>(value);
+  return os;
+}
+
+// These implement the variadic wrapper for the math operations.
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R>
+ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs,
+                                                                const R rhs) {
+  using Math = typename MathWrapper<M, L, R>::math;
+  return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
+                                                                        rhs);
+}
+
+// General purpose wrapper template for arithmetic operations.
+template <template <typename, typename, typename> class M,
+          typename L,
+          typename R,
+          typename... Args>
+ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
+ClampMathOp(const L lhs, const R rhs, const Args... args) {
+  return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
+}
+
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <);
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=);
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >);
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=);
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==);
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=);
+
+}  // namespace internal
+
+using internal::ClampedNumeric;
+using internal::MakeClampedNum;
+using internal::ClampMax;
+using internal::ClampMin;
+using internal::ClampAdd;
+using internal::ClampSub;
+using internal::ClampMul;
+using internal::ClampDiv;
+using internal::ClampMod;
+using internal::ClampLsh;
+using internal::ClampRsh;
+using internal::ClampAnd;
+using internal::ClampOr;
+using internal::ClampXor;
+
+}  // namespace base
+
+#endif  // BASE_NUMERICS_CLAMPED_MATH_H_
diff --git a/base/numerics/clamped_math_impl.h b/base/numerics/clamped_math_impl.h
new file mode 100644
index 0000000..7f8035c
--- /dev/null
+++ b/base/numerics/clamped_math_impl.h
@@ -0,0 +1,290 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
+#define BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math_shared_impl.h"
+
+namespace base {
+namespace internal {
+
+// This provides a small optimization that generates more compact code when one
+// of the components in an operation is a compile-time constant.
+template <typename T>
+constexpr bool IsCompileTimeConstant(const T v) {
+#if defined(__clang__) || defined(__GNUC__)
+  return __builtin_constant_p(v);
+#else
+  return false;
+#endif
+}
+
+// This is a wrapper to generate return the max or min for a supplied type.
+// If the argument is false, the returned value is the maximum. If true the
+// returned value is the minimum.
+template <typename T>
+constexpr T GetMaxOrMin(bool is_min) {
+  // For both signed and unsigned math the bit pattern for minimum is really
+  // just one plus the maximum. However, we have to cast to unsigned to ensure
+  // we get well-defined overflow semantics.
+  return as_unsigned(std::numeric_limits<T>::max()) + is_min;
+}
+
+template <typename T, typename U, class Enable = void>
+struct ClampedAddOp {};
+
+template <typename T, typename U>
+struct ClampedAddOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static V Do(T x, U y) {
+    V result;
+    return CheckedAddOp<T, U>::Do(x, y, &result)
+               ? result
+               // Prefer a compile-time constant (if we have one).
+               : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x)
+                                                         : IsValueNegative(y));
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedSubOp {};
+
+template <typename T, typename U>
+struct ClampedSubOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static V Do(T x, U y) {
+    V result;
+    return CheckedSubOp<T, U>::Do(x, y, &result)
+               ? result
+               // Prefer a compile-time constant (if we have one).
+               : GetMaxOrMin<V>(IsCompileTimeConstant(x) ? IsValueNegative(x)
+                                                         : !IsValueNegative(y));
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMulOp {};
+
+template <typename T, typename U>
+struct ClampedMulOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static V Do(T x, U y) {
+    V result;
+    return CheckedMulOp<T, U>::Do(x, y, &result)
+               ? result
+               : GetMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedDivOp {};
+
+template <typename T, typename U>
+struct ClampedDivOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static V Do(T x, U y) {
+    V result = SaturationDefaultLimits<V>::NaN();
+    return !x || CheckedDivOp<T, U>::Do(x, y, &result)
+               ? result
+               : GetMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedModOp {};
+
+template <typename T, typename U>
+struct ClampedModOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static V Do(T x, U y) {
+    V result;
+    return CheckedModOp<T, U>::Do(x, y, &result) ? result : x;
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedLshOp {};
+
+// Left shift. Non-zero values saturate in the direction of the sign. A zero
+// shifted by any value always results in zero.
+// Note: This class template supports left shifting negative values.
+template <typename T, typename U>
+struct ClampedLshOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = T;
+  template <typename V = result_type>
+  static V Do(T x, U shift) {
+    static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
+    V result = x;
+    return (shift < std::numeric_limits<T>::digits &&
+            CheckedMulOp<T, T>::Do(x, T(1) << shift, &result))
+               ? result
+               : (x ? GetMaxOrMin<V>(IsValueNegative(x)) : 0);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedRshOp {};
+
+// Right shift. Negative values saturate to -1. Positive or 0 saturates to 0.
+template <typename T, typename U>
+struct ClampedRshOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = T;
+  template <typename V = result_type>
+  static V Do(T x, U shift) {
+    static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
+    return shift < IntegerBitsPlusSign<T>::value
+               ? saturated_cast<V>(x >> shift)
+               // Signed right shift is odd, because it saturates to -1 or 0.
+               : as_unsigned(V(0)) - IsValueNegative(x);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedAndOp {};
+
+template <typename T, typename U>
+struct ClampedAndOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V>
+  static constexpr V Do(T x, U y) {
+    return static_cast<result_type>(x) & static_cast<result_type>(y);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedOrOp {};
+
+// For simplicity we promote to unsigned integers.
+template <typename T, typename U>
+struct ClampedOrOp<T,
+                   U,
+                   typename std::enable_if<std::is_integral<T>::value &&
+                                           std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V>
+  static constexpr V Do(T x, U y) {
+    return static_cast<result_type>(x) | static_cast<result_type>(y);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedXorOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct ClampedXorOp<T,
+                    U,
+                    typename std::enable_if<std::is_integral<T>::value &&
+                                            std::is_integral<U>::value>::type> {
+  using result_type = typename std::make_unsigned<
+      typename MaxExponentPromotion<T, U>::type>::type;
+  template <typename V>
+  static constexpr V Do(T x, U y) {
+    return static_cast<result_type>(x) ^ static_cast<result_type>(y);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMaxOp {};
+
+template <typename T, typename U>
+struct ClampedMaxOp<
+    T,
+    U,
+    typename std::enable_if<std::is_arithmetic<T>::value &&
+                            std::is_arithmetic<U>::value>::type> {
+  using result_type = typename MaxExponentPromotion<T, U>::type;
+  template <typename V = result_type>
+  static constexpr V Do(T x, U y) {
+    return IsGreater<T, U>::Test(x, y) ? saturated_cast<V>(x)
+                                       : saturated_cast<V>(y);
+  }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMinOp {};
+
+template <typename T, typename U>
+struct ClampedMinOp<
+    T,
+    U,
+    typename std::enable_if<std::is_arithmetic<T>::value &&
+                            std::is_arithmetic<U>::value>::type> {
+  using result_type = typename LowestValuePromotion<T, U>::type;
+  template <typename V = result_type>
+  static constexpr V Do(T x, U y) {
+    return IsLess<T, U>::Test(x, y) ? saturated_cast<V>(x)
+                                    : saturated_cast<V>(y);
+  }
+};
+
+// This is just boilerplate that wraps the standard floating point arithmetic.
+// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP)                              \
+  template <typename T, typename U>                                      \
+  struct Clamped##NAME##Op<                                              \
+      T, U,                                                              \
+      typename std::enable_if<std::is_floating_point<T>::value ||        \
+                              std::is_floating_point<U>::value>::type> { \
+    using result_type = typename MaxExponentPromotion<T, U>::type;       \
+    template <typename V = result_type>                                  \
+    static constexpr V Do(T x, U y) {                                    \
+      return saturated_cast<V>(x OP y);                                  \
+    }                                                                    \
+  };
+
+BASE_FLOAT_ARITHMETIC_OPS(Add, +)
+BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
+BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
+BASE_FLOAT_ARITHMETIC_OPS(Div, /)
+
+#undef BASE_FLOAT_ARITHMETIC_OPS
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
index b0ec279..c85e7c3 100644
--- a/base/numerics/safe_conversions.h
+++ b/base/numerics/safe_conversions.h
@@ -15,38 +15,6 @@
 
 namespace base {
 
-// The following are helper constexpr template functions and classes for safely
-// performing a range of conversions, assignments, and tests:
-//
-//  checked_cast<> - Analogous to static_cast<> for numeric types, except
-//      that it CHECKs that the specified numeric conversion will not overflow
-//      or underflow. NaN source will always trigger a CHECK.
-//      The default CHECK triggers a crash, but the handler can be overriden.
-//  saturated_cast<> - Analogous to static_cast<> for numeric types, except
-//      that it returns a saturated result when the specified numeric conversion
-//      would otherwise overflow or underflow. An NaN source returns 0 by
-//      default, but can be overridden to return a different result.
-//  strict_cast<> - Analogous to static_cast<> for numeric types, except that
-//      it will cause a compile failure if the destination type is not large
-//      enough to contain any value in the source type. It performs no runtime
-//      checking and thus introduces no runtime overhead.
-//  IsValueInRangeForNumericType<>() - A convenience function that returns true
-//      if the type supplied to the template parameter can represent the value
-//      passed as an argument to the function.
-//  IsValueNegative<>() - A convenience function that will accept any arithmetic
-//      type as an argument and will return whether the value is less than zero.
-//      Unsigned types always return false.
-//  SafeUnsignedAbs() - Returns the absolute value of the supplied integer
-//      parameter as an unsigned result (thus avoiding an overflow if the value
-//      is the signed, two's complement minimum).
-//  StrictNumeric<> - A wrapper type that performs assignments and copies via
-//      the strict_cast<> template, and can perform valid arithmetic comparisons
-//      across any range of arithmetic types. StrictNumeric is the return type
-//      for values extracted from a CheckedNumeric class instance. The raw
-//      arithmetic value is extracted via static_cast to the underlying type.
-//  MakeStrictNum() - Creates a new StrictNumeric from the underlying type of
-//      the supplied arithmetic or StrictNumeric type.
-
 // Convenience function that returns true if the supplied value is in range
 // for the destination type.
 template <typename Dst, typename Src>
@@ -82,21 +50,47 @@
              : CheckHandler::template HandleFailure<Dst>();
 }
 
+// as_signed<> returns the supplied integral value (or integral castable
+// Numeric template) cast as a signed integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_signed<
+    typename base::internal::UnderlyingType<Src>::type>::type
+as_signed(const Src value) {
+  static_assert(std::is_integral<decltype(as_signed(value))>::value,
+                "Argument must be a signed or unsigned integer type.");
+  return static_cast<decltype(as_signed(value))>(value);
+}
+
+// as_unsigned<> returns the supplied integral value (or integral castable
+// Numeric template) cast as an unsigned integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_unsigned<
+    typename base::internal::UnderlyingType<Src>::type>::type
+as_unsigned(const Src value) {
+  static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
+                "Argument must be a signed or unsigned integer type.");
+  return static_cast<decltype(as_unsigned(value))>(value);
+}
+
 // Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
+// You may provide your own limits (e.g. to saturated_cast) so long as you
+// implement all of the static constexpr member functions in the class below.
 template <typename T>
-struct SaturationDefaultHandler {
+struct SaturationDefaultLimits : public std::numeric_limits<T> {
   static constexpr T NaN() {
     return std::numeric_limits<T>::has_quiet_NaN
                ? std::numeric_limits<T>::quiet_NaN()
                : T();
   }
-  static constexpr T max() { return std::numeric_limits<T>::max(); }
+  using std::numeric_limits<T>::max;
   static constexpr T Overflow() {
     return std::numeric_limits<T>::has_infinity
                ? std::numeric_limits<T>::infinity()
                : std::numeric_limits<T>::max();
   }
-  static constexpr T lowest() { return std::numeric_limits<T>::lowest(); }
+  using std::numeric_limits<T>::lowest;
   static constexpr T Underflow() {
     return std::numeric_limits<T>::has_infinity
                ? std::numeric_limits<T>::infinity() * -1
@@ -124,8 +118,7 @@
 // overflow or underflow, and NaN assignment to an integral will return 0.
 // All boundary condition behaviors can be overriden with a custom handler.
 template <typename Dst,
-          template <typename>
-          class SaturationHandler = SaturationDefaultHandler,
+          template <typename> class SaturationHandler = SaturationDefaultLimits,
           typename Src>
 constexpr Dst saturated_cast(Src value) {
   using SrcType = typename UnderlyingType<Src>::type;
@@ -238,24 +231,23 @@
   return os;
 }
 
-#define STRICT_COMPARISON_OP(NAME, OP)                               \
-  template <typename L, typename R,                                  \
-            typename std::enable_if<                                 \
-                internal::IsStrictOp<L, R>::value>::type* = nullptr> \
-  constexpr bool operator OP(const L lhs, const R rhs) {             \
-    return SafeCompare<NAME, typename UnderlyingType<L>::type,       \
-                       typename UnderlyingType<R>::type>(lhs, rhs);  \
+#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP)              \
+  template <typename L, typename R,                                     \
+            typename std::enable_if<                                    \
+                internal::Is##CLASS##Op<L, R>::value>::type* = nullptr> \
+  constexpr bool operator OP(const L lhs, const R rhs) {                \
+    return SafeCompare<NAME, typename UnderlyingType<L>::type,          \
+                       typename UnderlyingType<R>::type>(lhs, rhs);     \
   }
 
-STRICT_COMPARISON_OP(IsLess, <);
-STRICT_COMPARISON_OP(IsLessOrEqual, <=);
-STRICT_COMPARISON_OP(IsGreater, >);
-STRICT_COMPARISON_OP(IsGreaterOrEqual, >=);
-STRICT_COMPARISON_OP(IsEqual, ==);
-STRICT_COMPARISON_OP(IsNotEqual, !=);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==);
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=);
 
-#undef STRICT_COMPARISON_OP
-};
+};  // namespace internal
 
 using internal::strict_cast;
 using internal::saturated_cast;
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index aef7135..713b8ef 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -549,6 +549,7 @@
   using type = typename ArithmeticOrUnderlyingEnum<T>::type;
   static const bool is_numeric = std::is_arithmetic<type>::value;
   static const bool is_checked = false;
+  static const bool is_clamped = false;
   static const bool is_strict = false;
 };
 
@@ -590,14 +591,17 @@
 struct IsClampedOp {
   static const bool value =
       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
-      (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
+      (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
+      !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
 };
 
 template <typename L, typename R>
 struct IsStrictOp {
   static const bool value =
       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
-      (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict);
+      (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
+      !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
+      !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
 };
 
 template <typename L, typename R>
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
index 810a13a..e30be90 100644
--- a/base/numerics/safe_math.h
+++ b/base/numerics/safe_math.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,6 +6,7 @@
 #define BASE_NUMERICS_SAFE_MATH_H_
 
 #include "base/numerics/checked_math.h"
+#include "base/numerics/clamped_math.h"
 #include "base/numerics/safe_conversions.h"
 
 #endif  // BASE_NUMERICS_SAFE_MATH_H_
diff --git a/base/numerics/safe_math_shared_impl.h b/base/numerics/safe_math_shared_impl.h
index 3e75bfe..c243e26 100644
--- a/base/numerics/safe_math_shared_impl.h
+++ b/base/numerics/safe_math_shared_impl.h
@@ -118,26 +118,27 @@
   template <typename L, typename R, typename... Args>                          \
   CLASS##Numeric<typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
       CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) {         \
-    return ChkMathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, args...);    \
+    return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs,        \
+                                                              args...);        \
   }
 
 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
-  /* Binary arithmetic operator for all CheckedNumeric operations. */          \
+  /* Binary arithmetic operator for all CLASS##Numeric operations. */          \
   template <typename L, typename R,                                            \
-            typename std::enable_if<IsCheckedOp<L, R>::value>::type* =         \
+            typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* =       \
                 nullptr>                                                       \
-  CheckedNumeric<typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>         \
+  CLASS##Numeric<typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>         \
   operator OP(const L lhs, const R rhs) {                                      \
     return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,      \
                                                                      rhs);     \
   }                                                                            \
-  /* Assignment arithmetic operator implementation from CheckedNumeric. */     \
+  /* Assignment arithmetic operator implementation from CLASS##Numeric. */     \
   template <typename L>                                                        \
   template <typename R>                                                        \
-  CheckedNumeric<L>& CheckedNumeric<L>::operator CMP_OP(const R rhs) {         \
+  CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(const R rhs) {         \
     return MathOp<CLASS##OP_NAME##Op>(rhs);                                    \
   }                                                                            \
-  /* Variadic arithmetic functions that return CheckedNumeric. */              \
+  /* Variadic arithmetic functions that return CLASS##Numeric. */              \
   BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
 
 }  // namespace internal
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index ec6d003..9fd9e8f 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -22,10 +22,12 @@
 
 using std::numeric_limits;
 using base::CheckedNumeric;
+using base::ClampedNumeric;
 using base::IsValidForType;
 using base::ValueOrDieForType;
 using base::ValueOrDefaultForType;
 using base::MakeCheckedNum;
+using base::MakeClampedNum;
 using base::CheckMax;
 using base::CheckMin;
 using base::CheckAdd;
@@ -35,9 +37,20 @@
 using base::CheckMod;
 using base::CheckLsh;
 using base::CheckRsh;
+using base::ClampMax;
+using base::ClampMin;
+using base::ClampAdd;
+using base::ClampSub;
+using base::ClampMul;
+using base::ClampDiv;
+using base::ClampMod;
+using base::ClampLsh;
+using base::ClampRsh;
+using base::as_unsigned;
 using base::checked_cast;
 using base::IsValueInRangeForNumericType;
 using base::IsValueNegative;
+using base::SaturationDefaultLimits;
 using base::SizeT;
 using base::StrictNumeric;
 using base::MakeStrictNum;
@@ -131,6 +144,17 @@
 U GetNumericValueForTest(const CheckedNumeric<U>& src) {
   return src.state_.value();
 }
+
+template <typename U>
+U GetNumericValueForTest(const ClampedNumeric<U>& src) {
+  return static_cast<U>(src);
+}
+
+template <typename U>
+U GetNumericValueForTest(const U& src) {
+  return src;
+}
+
 }  // namespace internal.
 }  // namespace base.
 
@@ -145,6 +169,36 @@
   }
 };
 
+template <typename T>
+constexpr T GetValue(const T& src) {
+  return src;
+}
+
+template <typename T, typename U>
+constexpr T GetValueAsDest(const U& src) {
+  return static_cast<T>(src);
+}
+
+template <typename T>
+constexpr T GetValue(const CheckedNumeric<T>& src) {
+  return src.template ValueOrDie<T, LogOnFailure>();
+}
+
+template <typename T, typename U>
+constexpr T GetValueAsDest(const CheckedNumeric<U>& src) {
+  return src.template ValueOrDie<T, LogOnFailure>();
+}
+
+template <typename T>
+constexpr T GetValue(const ClampedNumeric<T>& src) {
+  return static_cast<T>(src);
+}
+
+template <typename T, typename U>
+constexpr T GetValueAsDest(const ClampedNumeric<U>& src) {
+  return static_cast<T>(src);
+}
+
 // Helper macros to wrap displaying the conversion types and line numbers.
 #define TEST_EXPECTED_VALIDITY(expected, actual)                           \
   EXPECT_EQ(expected, (actual).template Cast<Dst>().IsValid())             \
@@ -156,12 +210,7 @@
 
 // We have to handle promotions, so infer the underlying type below from actual.
 #define TEST_EXPECTED_VALUE(expected, actual)                               \
-  EXPECT_EQ(static_cast<typename std::decay<decltype(actual)>::type::type>( \
-                expected),                                                  \
-            ((actual)                                                       \
-                 .template ValueOrDie<                                      \
-                     typename std::decay<decltype(actual)>::type::type,     \
-                     LogOnFailure>()))                                      \
+  EXPECT_EQ(GetValue(expected), GetValueAsDest<decltype(expected)>(actual)) \
       << "Result test: Value " << GetNumericValueForTest(actual) << " as "  \
       << dst << " on line " << line
 
@@ -190,18 +239,34 @@
     typename std::enable_if<numeric_limits<Dst>::is_integer &&
                                 numeric_limits<Dst>::is_signed,
                             int>::type = 0) {
-  using DstLimits = numeric_limits<Dst>;
+  using DstLimits = SaturationDefaultLimits<Dst>;
   TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::lowest()));
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()).Abs());
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
   TEST_EXPECTED_VALUE(DstLimits::max(),
                       MakeCheckedNum(-DstLimits::max()).Abs());
 
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      -ClampedNumeric<Dst>(DstLimits::lowest()));
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()).Abs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).Abs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      MakeClampedNum(-DstLimits::max()).Abs());
+
   TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + -1);
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1);
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) +
                         DstLimits::lowest());
 
+  TEST_EXPECTED_VALUE(DstLimits::max() - 1,
+                      ClampedNumeric<Dst>(DstLimits::max()) + -1);
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) + -1);
+  TEST_EXPECTED_VALUE(
+      DstLimits::Underflow(),
+      ClampedNumeric<Dst>(DstLimits::lowest()) + DstLimits::lowest());
+
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1);
   TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) - -1);
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) -
@@ -209,7 +274,20 @@
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) -
                         DstLimits::max());
 
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) - 1);
+  TEST_EXPECTED_VALUE(DstLimits::lowest() + 1,
+                      ClampedNumeric<Dst>(DstLimits::lowest()) - -1);
+  TEST_EXPECTED_VALUE(
+      DstLimits::Overflow(),
+      ClampedNumeric<Dst>(DstLimits::max()) - DstLimits::lowest());
+  TEST_EXPECTED_VALUE(
+      DstLimits::Underflow(),
+      ClampedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max());
+
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2);
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) * 2);
 
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) / -1);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2);
@@ -222,19 +300,42 @@
                       CheckedNumeric<Dst>(DstLimits::lowest()) * Dst(1));
   TEST_EXPECTED_VALUE(DstLimits::lowest(),
                       CheckedNumeric<Dst>(1) * Dst(DstLimits::lowest()));
-  TEST_EXPECTED_VALUE(DstLimits::lowest(),
-                      MakeCheckedNum(DstLimits::lowest()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(
+      typename std::make_unsigned<Dst>::type(0) - DstLimits::lowest(),
+      MakeCheckedNum(DstLimits::lowest()).UnsignedAbs());
   TEST_EXPECTED_VALUE(DstLimits::max(),
                       MakeCheckedNum(DstLimits::max()).UnsignedAbs());
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0).UnsignedAbs());
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).UnsignedAbs());
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).UnsignedAbs());
 
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) / -1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(-1) / 2);
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) * -1);
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      ClampedNumeric<Dst>(DstLimits::lowest() + 1) * Dst(-1));
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      ClampedNumeric<Dst>(-1) * Dst(DstLimits::lowest() + 1));
+  TEST_EXPECTED_VALUE(DstLimits::lowest(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) * Dst(1));
+  TEST_EXPECTED_VALUE(DstLimits::lowest(),
+                      ClampedNumeric<Dst>(1) * Dst(DstLimits::lowest()));
+  TEST_EXPECTED_VALUE(
+      typename std::make_unsigned<Dst>::type(0) - DstLimits::lowest(),
+      MakeClampedNum(DstLimits::lowest()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      MakeClampedNum(DstLimits::max()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0).UnsignedAbs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).UnsignedAbs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).UnsignedAbs());
+
   // Modulus is legal only for integers.
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
   TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2);
-  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-1) % -2);
+  TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % -2);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2);
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
   // Test all the different modulus combinations.
@@ -266,6 +367,44 @@
       0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1));
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one);
 
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(-1) % 2);
+  TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(-1) % -2);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % 2);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1);
+  ClampedNumeric<Dst> clamped_dst = 1;
+  TEST_EXPECTED_VALUE(0, clamped_dst %= 1);
+  TEST_EXPECTED_VALUE(Dst(1), ClampedNumeric<Dst>(1) % 0);
+  // Test bit shifts.
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(1)
+                          << (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(Dst(0), ClampedNumeric<Dst>(0)
+                                  << (IntegerBitsPlusSign<Dst>::value + 0U));
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::max()) << 1U);
+  TEST_EXPECTED_VALUE(
+      static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2U),
+      ClampedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2U));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0)
+                             << (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) << 0U);
+  TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) << 1U);
+  TEST_EXPECTED_VALUE(
+      0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value + 0U));
+  TEST_EXPECTED_VALUE(
+      0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(
+      -1, ClampedNumeric<Dst>(-1) >> (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(-1, ClampedNumeric<Dst>(DstLimits::lowest()) >>
+                              (IntegerBitsPlusSign<Dst>::value - 0U));
+
   TestStrictPointerMath<Dst>();
 }
 
@@ -277,7 +416,7 @@
     typename std::enable_if<numeric_limits<Dst>::is_integer &&
                                 !numeric_limits<Dst>::is_signed,
                             int>::type = 0) {
-  using DstLimits = numeric_limits<Dst>;
+  using DstLimits = SaturationDefaultLimits<Dst>;
   TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest()));
   TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs());
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1);
@@ -296,6 +435,29 @@
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0).UnsignedAbs());
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).UnsignedAbs());
 
+  TEST_EXPECTED_VALUE(0, -ClampedNumeric<Dst>(DstLimits::lowest()));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()).Abs());
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) + -1);
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) - 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) * 2);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) / 2);
+  TEST_EXPECTED_VALUE(0,
+                      ClampedNumeric<Dst>(DstLimits::lowest()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(
+      as_unsigned(
+          std::numeric_limits<typename std::make_signed<Dst>::type>::lowest()),
+      ClampedNumeric<typename std::make_signed<Dst>::type>(
+          std::numeric_limits<typename std::make_signed<Dst>::type>::lowest())
+          .UnsignedAbs());
+  TEST_EXPECTED_VALUE(DstLimits::lowest(),
+                      MakeClampedNum(DstLimits::lowest()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      MakeClampedNum(DstLimits::max()).UnsignedAbs());
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0).UnsignedAbs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).UnsignedAbs());
+
   // Modulus is legal only for integers.
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
@@ -350,6 +512,57 @@
                       CheckedNumeric<Dst>(0) ^ static_cast<Dst>(-1));
   TEST_EXPECTED_VALUE(DstLimits::max(), ~CheckedNumeric<Dst>(0));
 
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) % 2);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % 2);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 1);
+  ClampedNumeric<Dst> clamped_dst = 1;
+  TEST_EXPECTED_VALUE(0, clamped_dst %= 1);
+  // Test that div by 0 is avoided but returns invalid result.
+  TEST_EXPECTED_VALUE(Dst(1), ClampedNumeric<Dst>(1) % 0);
+  // Test bit shifts.
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(1)
+                          << as_unsigned(IntegerBitsPlusSign<Dst>::value));
+  TEST_EXPECTED_VALUE(Dst(0), ClampedNumeric<Dst>(0) << as_unsigned(
+                                  IntegerBitsPlusSign<Dst>::value));
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::max()) << 1U);
+  TEST_EXPECTED_VALUE(
+      static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1U),
+      ClampedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) << 0U);
+  TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) << 1U);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) >>
+                             as_unsigned(IntegerBitsPlusSign<Dst>::value));
+  TEST_EXPECTED_VALUE(
+      0, ClampedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1U));
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) & 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) & 0);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) & 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) & 0);
+  TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
+                      MakeClampedNum(DstLimits::max()) & -1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) | 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) | 0);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(0) | 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) | 0);
+  TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
+                      ClampedNumeric<Dst>(0) | static_cast<Dst>(-1));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) ^ 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) ^ 0);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(0) ^ 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) ^ 0);
+  TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
+                      ClampedNumeric<Dst>(0) ^ static_cast<Dst>(-1));
+  TEST_EXPECTED_VALUE(DstLimits::max(), ~ClampedNumeric<Dst>(0));
+
   TestStrictPointerMath<Dst>();
 }
 
@@ -359,7 +572,7 @@
     const char* dst,
     int line,
     typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
-  using DstLimits = numeric_limits<Dst>;
+  using DstLimits = SaturationDefaultLimits<Dst>;
   TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest()));
 
   TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs());
@@ -378,12 +591,39 @@
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2);
 
   TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2);
+
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      -ClampedNumeric<Dst>(DstLimits::lowest()));
+
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()).Abs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_VALUE(DstLimits::lowest() - 1,
+                      ClampedNumeric<Dst>(DstLimits::lowest()) + -1);
+  TEST_EXPECTED_VALUE(DstLimits::max() + 1,
+                      ClampedNumeric<Dst>(DstLimits::max()) + 1);
+  TEST_EXPECTED_VALUE(
+      DstLimits::Underflow(),
+      ClampedNumeric<Dst>(DstLimits::lowest()) + DstLimits::lowest());
+
+  TEST_EXPECTED_VALUE(
+      DstLimits::Overflow(),
+      ClampedNumeric<Dst>(DstLimits::max()) - DstLimits::lowest());
+  TEST_EXPECTED_VALUE(
+      DstLimits::Underflow(),
+      ClampedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max());
+
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                      ClampedNumeric<Dst>(DstLimits::lowest()) * 2);
+
+  TEST_EXPECTED_VALUE(-0.5, ClampedNumeric<Dst>(-1.0) / 2);
 }
 
 // Generic arithmetic tests.
 template <typename Dst>
 static void TestArithmetic(const char* dst, int line) {
-  using DstLimits = numeric_limits<Dst>;
+  using DstLimits = SaturationDefaultLimits<Dst>;
 
   EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid());
   EXPECT_EQ(false,
@@ -417,6 +657,27 @@
   checked_dst = 1;
   TEST_EXPECTED_VALUE(1, checked_dst /= 1);
 
+  TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) + ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) - ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) * ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, 1 + ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 - ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 * ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 / ClampedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, ClampedNumeric<Dst>(1) + 1);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) - 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) * 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / 1);
+  ClampedNumeric<Dst> clamped_dst = 1;
+  TEST_EXPECTED_VALUE(2, clamped_dst += 1);
+  clamped_dst = 1;
+  TEST_EXPECTED_VALUE(0, clamped_dst -= 1);
+  clamped_dst = 1;
+  TEST_EXPECTED_VALUE(1, clamped_dst *= 1);
+  clamped_dst = 1;
+  TEST_EXPECTED_VALUE(1, clamped_dst /= 1);
+
   // Generic negation.
   if (DstLimits::is_signed) {
     TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>());
@@ -424,6 +685,12 @@
     TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1));
     TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1),
                         -CheckedNumeric<Dst>(DstLimits::max()));
+
+    TEST_EXPECTED_VALUE(0, -ClampedNumeric<Dst>());
+    TEST_EXPECTED_VALUE(-1, -ClampedNumeric<Dst>(1));
+    TEST_EXPECTED_VALUE(1, -ClampedNumeric<Dst>(-1));
+    TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1),
+                        -ClampedNumeric<Dst>(DstLimits::max()));
   }
 
   // Generic absolute value.
@@ -432,6 +699,11 @@
   TEST_EXPECTED_VALUE(DstLimits::max(),
                       CheckedNumeric<Dst>(DstLimits::max()).Abs());
 
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>().Abs());
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1).Abs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      ClampedNumeric<Dst>(DstLimits::max()).Abs());
+
   // Generic addition.
   TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1));
   TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1));
@@ -441,6 +713,15 @@
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) +
                         DstLimits::max());
 
+  TEST_EXPECTED_VALUE(1, (ClampedNumeric<Dst>() + 1));
+  TEST_EXPECTED_VALUE(2, (ClampedNumeric<Dst>(1) + 1));
+  if (numeric_limits<Dst>::is_signed)
+    TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(-1) + 1));
+  TEST_EXPECTED_VALUE(DstLimits::lowest() + 1,
+                      ClampedNumeric<Dst>(DstLimits::lowest()) + 1);
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::max()) + DstLimits::max());
+
   // Generic subtraction.
   TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1));
   TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) - 1);
@@ -451,6 +732,17 @@
     TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - -1);
   }
 
+  TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(1) - 1));
+  TEST_EXPECTED_VALUE(DstLimits::max() - 1,
+                      ClampedNumeric<Dst>(DstLimits::max()) - 1);
+  if (numeric_limits<Dst>::is_signed) {
+    TEST_EXPECTED_VALUE(-1, (ClampedNumeric<Dst>() - 1));
+    TEST_EXPECTED_VALUE(-2, (ClampedNumeric<Dst>(-1) - 1));
+  } else {
+    TEST_EXPECTED_VALUE(DstLimits::max(),
+                        ClampedNumeric<Dst>(DstLimits::max()) - -1);
+  }
+
   // Generic multiplication.
   TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1));
   TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1));
@@ -467,6 +759,22 @@
   TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) *
                         DstLimits::max());
 
+  TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>() * 1));
+  TEST_EXPECTED_VALUE(1, (ClampedNumeric<Dst>(1) * 1));
+  TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(0) * 0));
+  if (numeric_limits<Dst>::is_signed) {
+    TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(-1) * 0));
+    TEST_EXPECTED_VALUE(0, (ClampedNumeric<Dst>(0) * -1));
+    TEST_EXPECTED_VALUE(-2, (ClampedNumeric<Dst>(-1) * 2));
+  } else {
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                        ClampedNumeric<Dst>(DstLimits::max()) * -2);
+    TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::max()) *
+                               ClampedNumeric<uintmax_t>(-2));
+  }
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                      ClampedNumeric<Dst>(DstLimits::max()) * DstLimits::max());
+
   // Generic division.
   TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1);
   TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
@@ -474,6 +782,17 @@
                       CheckedNumeric<Dst>(DstLimits::lowest()) / 2);
   TEST_EXPECTED_VALUE(DstLimits::max() / 2,
                       CheckedNumeric<Dst>(DstLimits::max()) / 2);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) / 0);
+
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>() / 1);
+  TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) / 1);
+  TEST_EXPECTED_VALUE(DstLimits::lowest() / 2,
+                      ClampedNumeric<Dst>(DstLimits::lowest()) / 2);
+  TEST_EXPECTED_VALUE(DstLimits::max() / 2,
+                      ClampedNumeric<Dst>(DstLimits::max()) / 2);
+  TEST_EXPECTED_VALUE(DstLimits::Overflow(), ClampedNumeric<Dst>(1) / 0);
+  TEST_EXPECTED_VALUE(DstLimits::Underflow(), ClampedNumeric<Dst>(-1) / 0);
+  TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) / 0);
 
   TestSpecializedArithmetic<Dst>(dst, line);
 }
@@ -605,8 +924,8 @@
 template <typename Dst, typename Src>
 struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
   static void Test(const char *dst, const char *src, int line) {
-    using SrcLimits = numeric_limits<Src>;
-    using DstLimits = numeric_limits<Dst>;
+    using SrcLimits = SaturationDefaultLimits<Src>;
+    using DstLimits = SaturationDefaultLimits<Dst>;
     // Integral to floating.
     static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) ||
                       // Not floating to integral and...
@@ -622,18 +941,26 @@
     TestStrictComparison<Dst, Src>();
 
     const CheckedNumeric<Dst> checked_dst = SrcLimits::max();
+    const ClampedNumeric<Dst> clamped_dst = SrcLimits::max();
     TEST_EXPECTED_SUCCESS(checked_dst);
+    TEST_EXPECTED_VALUE(Dst(SrcLimits::max()), clamped_dst);
     if (MaxExponent<Dst>::value > MaxExponent<Src>::value) {
       if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) {
         // At least twice larger type.
         TEST_EXPECTED_SUCCESS(SrcLimits::max() * checked_dst);
-
+        TEST_EXPECTED_VALUE(SrcLimits::max() * clamped_dst,
+                            Dst(SrcLimits::max()) * SrcLimits::max());
       } else {  // Larger, but not at least twice as large.
         TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst);
         TEST_EXPECTED_SUCCESS(checked_dst + 1);
+        TEST_EXPECTED_VALUE(DstLimits::Overflow(),
+                            SrcLimits::max() * clamped_dst);
+        TEST_EXPECTED_VALUE(Dst(SrcLimits::max()) + Dst(1),
+                            clamped_dst + Dst(1));
       }
     } else {  // Same width type.
       TEST_EXPECTED_FAILURE(checked_dst + 1);
+      TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + Dst(1));
     }
 
     TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
@@ -653,8 +980,8 @@
 template <typename Dst, typename Src>
 struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> {
   static void Test(const char *dst, const char *src, int line) {
-    using SrcLimits = numeric_limits<Src>;
-    using DstLimits = numeric_limits<Dst>;
+    using SrcLimits = SaturationDefaultLimits<Src>;
+    using DstLimits = SaturationDefaultLimits<Dst>;
     static_assert(SrcLimits::is_signed == DstLimits::is_signed,
                   "Destination and source sign must be the same");
     static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value,
@@ -664,9 +991,14 @@
 
     const CheckedNumeric<Dst> checked_dst;
     TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max());
-    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALUE(1, checked_dst + Src(1));
     TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max());
 
+    const ClampedNumeric<Dst> clamped_dst;
+    TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(1, clamped_dst + Src(1));
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst - SrcLimits::max());
+
     TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
     if (SrcLimits::is_iec559) {
@@ -689,10 +1021,12 @@
       }
     } else if (SrcLimits::is_signed) {
       TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_VALUE(-1, clamped_dst - static_cast<Src>(1));
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest());
       TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
     } else {
       TEST_EXPECTED_FAILURE(checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_VALUE(Dst(0), clamped_dst - static_cast<Src>(1));
       TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest());
     }
   }
@@ -701,8 +1035,8 @@
 template <typename Dst, typename Src>
 struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> {
   static void Test(const char *dst, const char *src, int line) {
-    using SrcLimits = numeric_limits<Src>;
-    using DstLimits = numeric_limits<Dst>;
+    using SrcLimits = SaturationDefaultLimits<Src>;
+    using DstLimits = SaturationDefaultLimits<Dst>;
     static_assert(MaxExponent<Dst>::value >= MaxExponent<Src>::value,
                   "Destination must be equal or wider than source.");
     static_assert(SrcLimits::is_signed, "Source must be signed");
@@ -713,8 +1047,17 @@
     const CheckedNumeric<Dst> checked_dst;
     TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max());
     TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_SUCCESS(checked_dst * static_cast<Src>(-1));
     TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest());
 
+    const ClampedNumeric<Dst> clamped_dst;
+    TEST_EXPECTED_VALUE(SrcLimits::max(), clamped_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                        clamped_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALUE(0, clamped_dst * static_cast<Src>(-1));
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                        clamped_dst + SrcLimits::lowest());
+
     TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest());
     TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
@@ -725,8 +1068,8 @@
 template <typename Dst, typename Src>
 struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> {
   static void Test(const char *dst, const char *src, int line) {
-    using SrcLimits = numeric_limits<Src>;
-    using DstLimits = numeric_limits<Dst>;
+    using SrcLimits = SaturationDefaultLimits<Src>;
+    using DstLimits = SaturationDefaultLimits<Dst>;
     static_assert(MaxExponent<Dst>::value < MaxExponent<Src>::value,
                   "Destination must be narrower than source.");
     static_assert(SrcLimits::is_signed, "Source must be signed.");
@@ -740,12 +1083,20 @@
     TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1));
     TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest());
 
+    const ClampedNumeric<Dst> clamped_dst;
+    TEST_EXPECTED_VALUE(1, clamped_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                        clamped_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALUE(DstLimits::Underflow(),
+                        clamped_dst + SrcLimits::lowest());
+
     TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
     TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
 
     // Additional saturation tests.
-    EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max())) << src;
+    EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max()));
     EXPECT_EQ(DstLimits::lowest(), saturated_cast<Dst>(SrcLimits::lowest()));
 
     if (SrcLimits::is_iec559) {
@@ -776,8 +1127,8 @@
 template <typename Dst, typename Src>
 struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> {
   static void Test(const char *dst, const char *src, int line) {
-    using SrcLimits = numeric_limits<Src>;
-    using DstLimits = numeric_limits<Dst>;
+    using SrcLimits = SaturationDefaultLimits<Src>;
+    using DstLimits = SaturationDefaultLimits<Dst>;
     static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value,
                   "Destination must be narrower or equal to source.");
     static_assert(!SrcLimits::is_signed, "Source must be unsigned.");
@@ -790,6 +1141,11 @@
     TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max());
     TEST_EXPECTED_VALUE(SrcLimits::lowest(), checked_dst + SrcLimits::lowest());
 
+    const ClampedNumeric<Dst> clamped_dst;
+    TEST_EXPECTED_VALUE(1, clamped_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(SrcLimits::lowest(), clamped_dst + SrcLimits::lowest());
+
     TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest());
     TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
@@ -1167,20 +1523,41 @@
 }
 
 TEST(SafeNumerics, VariadicNumericOperations) {
-  auto a = CheckAdd(1, 2UL, MakeCheckedNum(3LL), 4).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(a)::type>(10), a);
-  auto b = CheckSub(MakeCheckedNum(20.0), 2UL, 4).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b);
-  auto c = CheckMul(20.0, MakeCheckedNum(1), 5, 3UL).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c);
-  auto d = CheckDiv(20.0, 2.0, MakeCheckedNum(5LL), -4).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d);
-  auto e = CheckMod(MakeCheckedNum(20), 3).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(e)::type>(2), e);
-  auto f = CheckLsh(1, MakeCheckedNum(2)).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(f)::type>(4), f);
-  auto g = CheckRsh(4, MakeCheckedNum(2)).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(g)::type>(1), g);
-  auto h = CheckRsh(CheckAdd(1, 1, 1, 1), CheckSub(4, 2)).ValueOrDie();
-  EXPECT_EQ(static_cast<decltype(h)::type>(1), h);
+  {  // Synthetic scope to avoid variable naming collisions.
+    auto a = CheckAdd(1, 2UL, MakeCheckedNum(3LL), 4).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(a)::type>(10), a);
+    auto b = CheckSub(MakeCheckedNum(20.0), 2UL, 4).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b);
+    auto c = CheckMul(20.0, MakeCheckedNum(1), 5, 3UL).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c);
+    auto d = CheckDiv(20.0, 2.0, MakeCheckedNum(5LL), -4).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d);
+    auto e = CheckMod(MakeCheckedNum(20), 3).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(e)::type>(2), e);
+    auto f = CheckLsh(1, MakeCheckedNum(2)).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(f)::type>(4), f);
+    auto g = CheckRsh(4, MakeCheckedNum(2)).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(g)::type>(1), g);
+    auto h = CheckRsh(CheckAdd(1, 1, 1, 1), CheckSub(4, 2)).ValueOrDie();
+    EXPECT_EQ(static_cast<decltype(h)::type>(1), h);
+  }
+
+  {
+    auto a = ClampAdd(1, 2UL, MakeClampedNum(3LL), 4);
+    EXPECT_EQ(static_cast<decltype(a)::type>(10), a);
+    auto b = ClampSub(MakeClampedNum(20.0), 2UL, 4);
+    EXPECT_EQ(static_cast<decltype(b)::type>(14.0), b);
+    auto c = ClampMul(20.0, MakeClampedNum(1), 5, 3UL);
+    EXPECT_EQ(static_cast<decltype(c)::type>(300.0), c);
+    auto d = ClampDiv(20.0, 2.0, MakeClampedNum(5LL), -4);
+    EXPECT_EQ(static_cast<decltype(d)::type>(-.5), d);
+    auto e = ClampMod(MakeClampedNum(20), 3);
+    EXPECT_EQ(static_cast<decltype(e)::type>(2), e);
+    auto f = ClampLsh(1, MakeClampedNum(2U));
+    EXPECT_EQ(static_cast<decltype(f)::type>(4), f);
+    auto g = ClampRsh(4, MakeClampedNum(2U));
+    EXPECT_EQ(static_cast<decltype(g)::type>(1), g);
+    auto h = ClampRsh(ClampAdd(1, 1, 1, 1), ClampSub(4U, 2));
+    EXPECT_EQ(static_cast<decltype(h)::type>(1), h);
+  }
 }