Index: base/numerics/safe_numerics_unittest.cc |
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc |
index ec6d0037c9f0a0285844c179c9a40130fa4f9169..53bd1d9c38ec91171b0b8223a33d0356c0223720 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; |
dcheng
2017/06/28 07:25:06
FWIW, I think we usually dump tests into the same
jschuh
2017/06/28 12:32:38
Now you tell me.
|
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::CheckDiv; |
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 @@ template <typename U> |
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 @@ struct LogOnFailure { |
} |
}; |
+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 @@ struct LogOnFailure { |
// 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 @@ static void TestSpecializedArithmetic( |
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 @@ static void TestSpecializedArithmetic( |
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 @@ static void TestSpecializedArithmetic( |
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. |
@@ -250,8 +351,8 @@ static void TestSpecializedArithmetic( |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) |
<< (IntegerBitsPlusSign<Dst>::value - 1)); |
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) |
- << IntegerBitsPlusSign<Dst>::value); |
+ TEST_EXPECTED_VALUE(Dst(0), CheckedNumeric<Dst>(0) |
+ << IntegerBitsPlusSign<Dst>::value); |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); |
TEST_EXPECTED_VALUE( |
static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2), |
@@ -266,6 +367,40 @@ static void TestSpecializedArithmetic( |
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)); |
+ |
TestStrictPointerMath<Dst>(); |
} |
@@ -277,7 +412,7 @@ static void TestSpecializedArithmetic( |
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 +431,29 @@ static void TestSpecializedArithmetic( |
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); |
@@ -317,8 +475,8 @@ static void TestSpecializedArithmetic( |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) |
<< IntegerBitsPlusSign<Dst>::value); |
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) |
- << IntegerBitsPlusSign<Dst>::value); |
+ TEST_EXPECTED_VALUE(Dst(0), CheckedNumeric<Dst>(0) |
+ << IntegerBitsPlusSign<Dst>::value); |
TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); |
TEST_EXPECTED_VALUE( |
static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1), |
@@ -350,6 +508,60 @@ static void TestSpecializedArithmetic( |
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_EXPECTED_VALUE(DstLimits::Overflow(), |
+ ClampedNumeric<Dst>(1) |
+ << as_unsigned(IntegerBitsPlusSign<Dst>::value)); |
+ // 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(), |
+ MakeCheckedNum(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 +571,7 @@ void TestSpecializedArithmetic( |
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 +590,39 @@ void TestSpecializedArithmetic( |
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 +656,27 @@ static void TestArithmetic(const char* dst, int line) { |
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 +684,12 @@ static void TestArithmetic(const char* dst, int line) { |
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 +698,11 @@ static void TestArithmetic(const char* dst, int line) { |
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 +712,15 @@ static void TestArithmetic(const char* dst, int line) { |
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 +731,17 @@ static void TestArithmetic(const char* dst, int line) { |
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 +758,22 @@ static void TestArithmetic(const char* dst, int line) { |
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); |
@@ -475,6 +782,13 @@ static void TestArithmetic(const char* dst, int line) { |
TEST_EXPECTED_VALUE(DstLimits::max() / 2, |
CheckedNumeric<Dst>(DstLimits::max()) / 2); |
+ 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); |
+ |
TestSpecializedArithmetic<Dst>(dst, line); |
} |
@@ -605,8 +919,8 @@ void TestStrictComparison() { |
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 +936,26 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { |
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 +975,8 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { |
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 +986,14 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { |
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 +1016,12 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { |
} |
} 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 +1030,8 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { |
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 +1042,17 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { |
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 +1063,8 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { |
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 +1078,20 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { |
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 +1122,8 @@ struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { |
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 +1136,11 @@ struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { |
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 +1518,41 @@ TEST(SafeNumerics, CompoundNumericOperations) { |
} |
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)); |
dcheng
2017/06/28 07:25:06
How come this needs an explicit U while the checke
jschuh
2017/06/28 12:32:38
Conscious API decision. Negative shift is always w
|
+ 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); |
+ } |
} |