1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846 |
- // Copyright 2013 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.
- #include <stddef.h>
- #include <stdint.h>
- #include <limits>
- #include <type_traits>
- #include "base/compiler_specific.h"
- #include "build/build_config.h"
- // WARNING: This block must come before the base/numerics headers are included.
- // These tests deliberately cause arithmetic boundary errors. If the compiler is
- // aggressive enough, it can const detect these errors, so we disable warnings.
- #if BUILDFLAG(IS_WIN)
- #pragma warning(disable : 4756) // Arithmetic overflow.
- #pragma warning(disable : 4293) // Invalid shift.
- #endif
- // This may not need to come before the base/numerics headers, but let's keep
- // it close to the MSVC equivalent.
- #if defined(__clang__)
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Winteger-overflow"
- #endif
- #include "base/logging.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/numerics/safe_math.h"
- #include "base/test/gtest_util.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
- #include <mmintrin.h>
- #endif
- namespace base {
- namespace internal {
- using std::numeric_limits;
- // This is a helper function for finding the maximum value in Src that can be
- // wholy represented as the destination floating-point type.
- template <typename Dst, typename Src>
- Dst GetMaxConvertibleToFloat() {
- using DstLimits = numeric_limits<Dst>;
- using SrcLimits = numeric_limits<Src>;
- static_assert(SrcLimits::is_specialized, "Source must be numeric.");
- static_assert(DstLimits::is_specialized, "Destination must be numeric.");
- CHECK(DstLimits::is_iec559);
- if (SrcLimits::digits <= DstLimits::digits &&
- MaxExponent<Src>::value <= MaxExponent<Dst>::value)
- return SrcLimits::max();
- Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0);
- while (max != static_cast<Src>(static_cast<Dst>(max))) {
- max /= 2;
- }
- return static_cast<Dst>(max);
- }
- // Test corner case promotions used
- static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int8_t>::value, "");
- static_assert(IsIntegerArithmeticSafe<int32_t, int16_t, int8_t>::value, "");
- static_assert(IsIntegerArithmeticSafe<int32_t, int8_t, int16_t>::value, "");
- static_assert(!IsIntegerArithmeticSafe<int32_t, int32_t, int8_t>::value, "");
- static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, "");
- static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, "");
- static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, "");
- static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, "");
- static_assert(
- std::is_same<BigEnoughPromotion<int16_t, int8_t>::type, int16_t>::value,
- "");
- static_assert(
- std::is_same<BigEnoughPromotion<int32_t, uint32_t>::type, int64_t>::value,
- "");
- static_assert(
- std::is_same<BigEnoughPromotion<intmax_t, int8_t>::type, intmax_t>::value,
- "");
- static_assert(
- std::is_same<BigEnoughPromotion<uintmax_t, int8_t>::type, uintmax_t>::value,
- "");
- static_assert(BigEnoughPromotion<int16_t, int8_t>::is_contained, "");
- static_assert(BigEnoughPromotion<int32_t, uint32_t>::is_contained, "");
- static_assert(BigEnoughPromotion<intmax_t, int8_t>::is_contained, "");
- static_assert(!BigEnoughPromotion<uintmax_t, int8_t>::is_contained, "");
- static_assert(
- std::is_same<FastIntegerArithmeticPromotion<int16_t, int8_t>::type,
- int32_t>::value,
- "");
- static_assert(
- std::is_same<FastIntegerArithmeticPromotion<int32_t, uint32_t>::type,
- int64_t>::value,
- "");
- static_assert(
- std::is_same<FastIntegerArithmeticPromotion<intmax_t, int8_t>::type,
- intmax_t>::value,
- "");
- static_assert(
- std::is_same<FastIntegerArithmeticPromotion<uintmax_t, int8_t>::type,
- uintmax_t>::value,
- "");
- static_assert(FastIntegerArithmeticPromotion<int16_t, int8_t>::is_contained,
- "");
- static_assert(FastIntegerArithmeticPromotion<int32_t, uint32_t>::is_contained,
- "");
- static_assert(!FastIntegerArithmeticPromotion<intmax_t, int8_t>::is_contained,
- "");
- static_assert(!FastIntegerArithmeticPromotion<uintmax_t, int8_t>::is_contained,
- "");
- // Test compile-time (constexpr) evaluation of checking and saturation.
- constexpr int32_t kIntOne = 1;
- static_assert(1 == checked_cast<uint8_t>(kIntOne), "");
- static_assert(1 == saturated_cast<uint8_t>(kIntOne), "");
- static_assert(2U == MakeClampedNum(kIntOne) + 1, "");
- static_assert(2U == (MakeCheckedNum(kIntOne) + 1).ValueOrDie(), "");
- static_assert(0U == MakeClampedNum(kIntOne) - 1, "");
- static_assert(0U == (MakeCheckedNum(kIntOne) - 1).ValueOrDie(), "");
- static_assert(-1 == -MakeClampedNum(kIntOne), "");
- static_assert(-1 == (-MakeCheckedNum(kIntOne)).ValueOrDie(), "");
- static_assert(1U == MakeClampedNum(kIntOne) * 1, "");
- static_assert(1U == (MakeCheckedNum(kIntOne) * 1).ValueOrDie(), "");
- static_assert(1U == MakeClampedNum(kIntOne) / 1, "");
- static_assert(1U == (MakeCheckedNum(kIntOne) / 1).ValueOrDie(), "");
- static_assert(1 == MakeClampedNum(-kIntOne).Abs(), "");
- static_assert(1 == MakeCheckedNum(-kIntOne).Abs().ValueOrDie(), "");
- static_assert(1U == MakeClampedNum(kIntOne) % 2, "");
- static_assert(1U == (MakeCheckedNum(kIntOne) % 2).ValueOrDie(), "");
- static_assert(0U == MakeClampedNum(kIntOne) >> 1U, "");
- static_assert(0U == (MakeCheckedNum(kIntOne) >> 1U).ValueOrDie(), "");
- static_assert(2U == MakeClampedNum(kIntOne) << 1U, "");
- static_assert(2U == (MakeCheckedNum(kIntOne) << 1U).ValueOrDie(), "");
- static_assert(1 == MakeClampedNum(kIntOne) & 1U, "");
- static_assert(1 == (MakeCheckedNum(kIntOne) & 1U).ValueOrDie(), "");
- static_assert(1 == MakeClampedNum(kIntOne) | 1U, "");
- static_assert(1 == (MakeCheckedNum(kIntOne) | 1U).ValueOrDie(), "");
- static_assert(0 == MakeClampedNum(kIntOne) ^ 1U, "");
- static_assert(0 == (MakeCheckedNum(kIntOne) ^ 1U).ValueOrDie(), "");
- constexpr float kFloatOne = 1.0;
- static_assert(1 == int{checked_cast<int8_t>(kFloatOne)}, "");
- static_assert(1 == int{saturated_cast<int8_t>(kFloatOne)}, "");
- static_assert(2U == unsigned{MakeClampedNum(kFloatOne) + 1}, "");
- static_assert(2U ==
- (MakeCheckedNum(kFloatOne) + 1).Cast<unsigned>().ValueOrDie(),
- "");
- static_assert(0U == unsigned{MakeClampedNum(kFloatOne) - 1}, "");
- static_assert(0U ==
- (MakeCheckedNum(kFloatOne) - 1).Cast<unsigned>().ValueOrDie(),
- "");
- static_assert(-1 == int{-MakeClampedNum(kFloatOne)}, "");
- static_assert(-1 == (-MakeCheckedNum(kFloatOne)).Cast<int>().ValueOrDie(), "");
- static_assert(1U == unsigned{MakeClampedNum(kFloatOne) * 1}, "");
- static_assert(1U ==
- (MakeCheckedNum(kFloatOne) * 1).Cast<unsigned>().ValueOrDie(),
- "");
- static_assert(1U == unsigned{MakeClampedNum(kFloatOne) / 1}, "");
- static_assert(1U ==
- (MakeCheckedNum(kFloatOne) / 1).Cast<unsigned>().ValueOrDie(),
- "");
- static_assert(1 == int{MakeClampedNum(-kFloatOne).Abs()}, "");
- static_assert(1 == MakeCheckedNum(-kFloatOne).Abs().Cast<int>().ValueOrDie(),
- "");
- 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;
- }
- // Logs the ValueOrDie() failure instead of crashing.
- struct LogOnFailure {
- template <typename T>
- static T HandleFailure() {
- LOG(WARNING) << "ValueOrDie() failed unexpectedly.";
- return T();
- }
- };
- 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()) \
- << "Result test: Value " << GetNumericValueForTest(actual) << " as " \
- << dst << " on line " << line
- #define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual)
- #define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual)
- // We have to handle promotions, so infer the underlying type below from actual.
- #define TEST_EXPECTED_VALUE(expected, actual) \
- EXPECT_EQ(GetValue(expected), GetValueAsDest<decltype(expected)>(actual)) \
- << "Result test: Value " << GetNumericValueForTest(actual) << " as " \
- << dst << " on line " << line
- // Test the simple pointer arithmetic overrides.
- template <typename Dst>
- void TestStrictPointerMath() {
- Dst dummy_value = 0;
- Dst* dummy_ptr = &dummy_value;
- static const Dst kDummyOffset = 2; // Don't want to go too far.
- EXPECT_EQ(dummy_ptr + kDummyOffset,
- dummy_ptr + StrictNumeric<Dst>(kDummyOffset));
- EXPECT_EQ(dummy_ptr - kDummyOffset,
- dummy_ptr - StrictNumeric<Dst>(kDummyOffset));
- EXPECT_NE(dummy_ptr, dummy_ptr + StrictNumeric<Dst>(kDummyOffset));
- EXPECT_NE(dummy_ptr, dummy_ptr - StrictNumeric<Dst>(kDummyOffset));
- EXPECT_DEATH_IF_SUPPORTED(
- dummy_ptr + StrictNumeric<size_t>(std::numeric_limits<size_t>::max()),
- "");
- }
- // Signed integer arithmetic.
- template <typename Dst>
- static void TestSpecializedArithmetic(
- const char* dst,
- int line,
- typename std::enable_if<numeric_limits<Dst>::is_integer &&
- numeric_limits<Dst>::is_signed,
- int>::type = 0) {
- 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()) -
- DstLimits::lowest());
- 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);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * -1);
- TEST_EXPECTED_VALUE(DstLimits::max(),
- CheckedNumeric<Dst>(DstLimits::lowest() + 1) * Dst(-1));
- TEST_EXPECTED_VALUE(DstLimits::max(),
- CheckedNumeric<Dst>(-1) * Dst(DstLimits::lowest() + 1));
- TEST_EXPECTED_VALUE(DstLimits::lowest(),
- CheckedNumeric<Dst>(DstLimits::lowest()) * Dst(1));
- TEST_EXPECTED_VALUE(DstLimits::lowest(),
- CheckedNumeric<Dst>(1) * Dst(DstLimits::lowest()));
- 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>(0) % 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) % 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) % -1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) % -2);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % -1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % -2);
- TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) % 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) % -1);
- TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % -2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % -1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % -2);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::max()) % 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::max()) % -1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % -2);
- // Test all the different modulus combinations.
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
- CheckedNumeric<Dst> checked_dst = 1;
- TEST_EXPECTED_VALUE(0, checked_dst %= 1);
- // Test that div by 0 is avoided but returns invalid result.
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) % 0);
- // Test bit shifts.
- volatile Dst negative_one = -1;
- 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_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1);
- TEST_EXPECTED_VALUE(
- static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2),
- CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2));
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0)
- << (IntegerBitsPlusSign<Dst>::value - 1));
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0);
- TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >>
- IntegerBitsPlusSign<Dst>::value);
- TEST_EXPECTED_VALUE(
- 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>(0) % 2);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) % 1);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) % -1);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(0) % -2);
- TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(1) % 2);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(1) % 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>(-1) % 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(0, ClampedNumeric<Dst>(DstLimits::lowest()) % 1);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % -1);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::lowest()) % -2);
- TEST_EXPECTED_VALUE(1, ClampedNumeric<Dst>(DstLimits::max()) % 2);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::max()) % 1);
- TEST_EXPECTED_VALUE(0, ClampedNumeric<Dst>(DstLimits::max()) % -1);
- 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>();
- }
- // Unsigned integer arithmetic.
- template <typename Dst>
- static void TestSpecializedArithmetic(
- const char* dst,
- int line,
- typename std::enable_if<numeric_limits<Dst>::is_integer &&
- !numeric_limits<Dst>::is_signed,
- int>::type = 0) {
- 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);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) * 2);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
- TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).UnsignedAbs());
- TEST_EXPECTED_SUCCESS(
- CheckedNumeric<typename std::make_signed<Dst>::type>(
- std::numeric_limits<typename std::make_signed<Dst>::type>::lowest())
- .UnsignedAbs());
- TEST_EXPECTED_VALUE(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(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);
- 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.
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
- CheckedNumeric<Dst> checked_dst = 1;
- TEST_EXPECTED_VALUE(0, checked_dst %= 1);
- // Test that div by 0 is avoided but returns invalid result.
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) % 0);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1)
- << IntegerBitsPlusSign<Dst>::value);
- // Test bit shifts.
- volatile int negative_one = -1;
- 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_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1);
- TEST_EXPECTED_VALUE(
- static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1),
- CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1));
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0);
- TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >>
- IntegerBitsPlusSign<Dst>::value);
- TEST_EXPECTED_VALUE(
- 0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1));
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) & 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) & 0);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) & 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) & 0);
- TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
- MakeCheckedNum(DstLimits::max()) & -1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) | 1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) | 0);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(0) | 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) | 0);
- TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
- CheckedNumeric<Dst>(0) | static_cast<Dst>(-1));
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) ^ 1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) ^ 0);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(0) ^ 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) ^ 0);
- TEST_EXPECTED_VALUE(std::numeric_limits<Dst>::max(),
- 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>();
- }
- // Floating point arithmetic.
- template <typename Dst>
- void TestSpecializedArithmetic(
- const char* dst,
- int line,
- typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
- using DstLimits = SaturationDefaultLimits<Dst>;
- TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest()));
- TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs());
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
- TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + -1);
- TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + 1);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) +
- DstLimits::lowest());
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) -
- DstLimits::lowest());
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) -
- DstLimits::max());
- 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 = SaturationDefaultLimits<Dst>;
- EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid());
- EXPECT_EQ(false, CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
- DstLimits::max())
- .IsValid());
- EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie());
- EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1));
- EXPECT_EQ(static_cast<Dst>(1),
- CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
- DstLimits::max())
- .ValueOrDefault(1));
- // Test the operator combinations.
- TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1));
- TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1);
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1);
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
- CheckedNumeric<Dst> checked_dst = 1;
- TEST_EXPECTED_VALUE(2, checked_dst += 1);
- checked_dst = 1;
- TEST_EXPECTED_VALUE(0, checked_dst -= 1);
- checked_dst = 1;
- TEST_EXPECTED_VALUE(1, checked_dst *= 1);
- 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>());
- TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1));
- 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()));
- // The runtime paths for saturated negation differ significantly from what
- // gets evaluated at compile-time. Making this test volatile forces the
- // compiler to generate code rather than fold constant expressions.
- volatile Dst value = Dst(0);
- TEST_EXPECTED_VALUE(0, -MakeClampedNum(value));
- value = Dst(1);
- TEST_EXPECTED_VALUE(-1, -MakeClampedNum(value));
- value = Dst(2);
- TEST_EXPECTED_VALUE(-2, -MakeClampedNum(value));
- value = Dst(-1);
- TEST_EXPECTED_VALUE(1, -MakeClampedNum(value));
- value = Dst(-2);
- TEST_EXPECTED_VALUE(2, -MakeClampedNum(value));
- value = DstLimits::max();
- TEST_EXPECTED_VALUE(Dst(DstLimits::max() * -1), -MakeClampedNum(value));
- value = Dst(-1 * DstLimits::max());
- TEST_EXPECTED_VALUE(DstLimits::max(), -MakeClampedNum(value));
- value = DstLimits::lowest();
- TEST_EXPECTED_VALUE(DstLimits::max(), -MakeClampedNum(value));
- }
- // Generic absolute value.
- TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs());
- TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs());
- 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));
- if (numeric_limits<Dst>::is_signed)
- TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1));
- TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + 1);
- 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);
- if (numeric_limits<Dst>::is_signed) {
- TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1));
- TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1));
- } else {
- 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));
- TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0));
- if (numeric_limits<Dst>::is_signed) {
- TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0));
- TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1));
- TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2));
- } else {
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) * -2);
- TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) *
- CheckedNumeric<uintmax_t>(-2));
- }
- 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);
- TEST_EXPECTED_VALUE(DstLimits::lowest() / 2,
- 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);
- }
- // Helper macro to wrap displaying the conversion types and line numbers.
- #define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__)
- TEST(SafeNumerics, SignedIntegerMath) {
- TEST_ARITHMETIC(int8_t);
- TEST_ARITHMETIC(int16_t);
- TEST_ARITHMETIC(int);
- TEST_ARITHMETIC(intptr_t);
- TEST_ARITHMETIC(intmax_t);
- }
- TEST(SafeNumerics, UnsignedIntegerMath) {
- TEST_ARITHMETIC(uint8_t);
- TEST_ARITHMETIC(uint16_t);
- TEST_ARITHMETIC(unsigned int);
- TEST_ARITHMETIC(uintptr_t);
- TEST_ARITHMETIC(uintmax_t);
- }
- TEST(SafeNumerics, FloatingPointMath) {
- TEST_ARITHMETIC(float);
- TEST_ARITHMETIC(double);
- }
- // Enumerates the five different conversions types we need to test.
- enum NumericConversionType {
- SIGN_PRESERVING_VALUE_PRESERVING,
- SIGN_PRESERVING_NARROW,
- SIGN_TO_UNSIGN_WIDEN_OR_EQUAL,
- SIGN_TO_UNSIGN_NARROW,
- UNSIGN_TO_SIGN_NARROW_OR_EQUAL,
- };
- // Template covering the different conversion tests.
- template <typename Dst, typename Src, NumericConversionType conversion>
- struct TestNumericConversion {};
- enum RangeConstraint {
- RANGE_VALID = 0x0, // Value can be represented by the destination type.
- RANGE_UNDERFLOW = 0x1, // Value would underflow.
- RANGE_OVERFLOW = 0x2, // Value would overflow.
- RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN).
- };
- // These are some wrappers to make the tests a bit cleaner.
- constexpr RangeConstraint RangeCheckToEnum(const RangeCheck constraint) {
- return static_cast<RangeConstraint>(
- static_cast<int>(constraint.IsOverflowFlagSet()) << 1 |
- static_cast<int>(constraint.IsUnderflowFlagSet()));
- }
- // EXPECT_EQ wrappers providing specific detail on test failures.
- #define TEST_EXPECTED_RANGE(expected, actual) \
- EXPECT_EQ(expected, \
- RangeCheckToEnum(DstRangeRelationToSrcRange<Dst>(actual))) \
- << "Conversion test: " << src << " value " << actual << " to " << dst \
- << " on line " << line
- template <typename Dst, typename Src>
- void TestStrictComparison(const char* dst, const char* src, int line) {
- using DstLimits = numeric_limits<Dst>;
- using SrcLimits = numeric_limits<Src>;
- static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < DstLimits::max(), "");
- static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < SrcLimits::max(), "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) >= DstLimits::max()),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) >= SrcLimits::max()),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::lowest()) <= DstLimits::max(),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::lowest()) <= SrcLimits::max(),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) > DstLimits::max()),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) > SrcLimits::max()),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) > DstLimits::lowest(), "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) > SrcLimits::lowest(), "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= DstLimits::lowest()),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::max()) <= SrcLimits::lowest()),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) >= DstLimits::lowest(),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) >= SrcLimits::lowest(),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < DstLimits::lowest()),
- "");
- static_assert(!(StrictNumeric<Src>(SrcLimits::max()) < SrcLimits::lowest()),
- "");
- static_assert(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(1),
- "");
- static_assert(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(0),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) != static_cast<Dst>(0),
- "");
- static_assert(StrictNumeric<Src>(SrcLimits::max()) != DstLimits::lowest(),
- "");
- static_assert(
- !(StrictNumeric<Src>(static_cast<Src>(1)) != static_cast<Dst>(1)), "");
- static_assert(
- !(StrictNumeric<Src>(static_cast<Src>(1)) == static_cast<Dst>(0)), "");
- // Due to differences in float handling between compilers, these aren't
- // compile-time constants everywhere. So, we use run-time tests.
- EXPECT_EQ(
- SrcLimits::max(),
- MakeCheckedNum(SrcLimits::max()).Max(DstLimits::lowest()).ValueOrDie());
- EXPECT_EQ(
- DstLimits::max(),
- MakeCheckedNum(SrcLimits::lowest()).Max(DstLimits::max()).ValueOrDie());
- EXPECT_EQ(
- DstLimits::lowest(),
- MakeCheckedNum(SrcLimits::max()).Min(DstLimits::lowest()).ValueOrDie());
- EXPECT_EQ(
- SrcLimits::lowest(),
- MakeCheckedNum(SrcLimits::lowest()).Min(DstLimits::max()).ValueOrDie());
- EXPECT_EQ(SrcLimits::lowest(), CheckMin(MakeStrictNum(1), MakeCheckedNum(0),
- DstLimits::max(), SrcLimits::lowest())
- .ValueOrDie());
- EXPECT_EQ(DstLimits::max(), CheckMax(MakeStrictNum(1), MakeCheckedNum(0),
- DstLimits::max(), SrcLimits::lowest())
- .ValueOrDie());
- EXPECT_EQ(SrcLimits::max(),
- MakeClampedNum(SrcLimits::max()).Max(DstLimits::lowest()));
- EXPECT_EQ(DstLimits::max(),
- MakeClampedNum(SrcLimits::lowest()).Max(DstLimits::max()));
- EXPECT_EQ(DstLimits::lowest(),
- MakeClampedNum(SrcLimits::max()).Min(DstLimits::lowest()));
- EXPECT_EQ(SrcLimits::lowest(),
- MakeClampedNum(SrcLimits::lowest()).Min(DstLimits::max()));
- EXPECT_EQ(SrcLimits::lowest(),
- ClampMin(MakeStrictNum(1), MakeClampedNum(0), DstLimits::max(),
- SrcLimits::lowest()));
- EXPECT_EQ(DstLimits::max(), ClampMax(MakeStrictNum(1), MakeClampedNum(0),
- DstLimits::max(), SrcLimits::lowest()));
- if (IsValueInRangeForNumericType<Dst>(SrcLimits::max())) {
- TEST_EXPECTED_VALUE(Dst(SrcLimits::max()), (CommonMax<Dst, Src>()));
- TEST_EXPECTED_VALUE(Dst(SrcLimits::max()),
- (CommonMaxOrMin<Dst, Src>(false)));
- } else {
- TEST_EXPECTED_VALUE(DstLimits::max(), (CommonMax<Dst, Src>()));
- TEST_EXPECTED_VALUE(DstLimits::max(), (CommonMaxOrMin<Dst, Src>(false)));
- }
- if (IsValueInRangeForNumericType<Dst>(SrcLimits::lowest())) {
- TEST_EXPECTED_VALUE(Dst(SrcLimits::lowest()), (CommonMin<Dst, Src>()));
- TEST_EXPECTED_VALUE(Dst(SrcLimits::lowest()),
- (CommonMaxOrMin<Dst, Src>(true)));
- } else {
- TEST_EXPECTED_VALUE(DstLimits::lowest(), (CommonMin<Dst, Src>()));
- TEST_EXPECTED_VALUE(DstLimits::lowest(), (CommonMaxOrMin<Dst, Src>(true)));
- }
- }
- 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 = SaturationDefaultLimits<Src>;
- using DstLimits = SaturationDefaultLimits<Dst>;
- // Integral to floating.
- static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) ||
- // Not floating to integral and...
- (!(DstLimits::is_integer && SrcLimits::is_iec559) &&
- // Same sign, same numeric, source is narrower or same.
- ((SrcLimits::is_signed == DstLimits::is_signed &&
- MaxExponent<Dst>::value >= MaxExponent<Src>::value) ||
- // Or signed destination and source is smaller
- (DstLimits::is_signed &&
- MaxExponent<Dst>::value >= MaxExponent<Src>::value))),
- "Comparison must be sign preserving and value preserving");
- TestStrictComparison<Dst, Src>(dst, src, line);
- 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()) * Dst(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());
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
- if (SrcLimits::is_iec559) {
- TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1));
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
- TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- } else if (numeric_limits<Src>::is_signed) {
- // This block reverses the Src to Dst relationship so we don't have to
- // complicate the test macros.
- if (!std::is_same<Src, Dst>::value) {
- TEST_EXPECTED_SUCCESS(CheckDiv(SrcLimits::lowest(), Dst(-1)));
- }
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
- TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest());
- }
- }
- };
- 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 = 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,
- "Destination must be narrower than source");
- TestStrictComparison<Dst, Src>(dst, src, line);
- const CheckedNumeric<Dst> checked_dst;
- TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max());
- TEST_EXPECTED_VALUE(1, checked_dst + Src(1));
- TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max());
- 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());
- clamped_dst += SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst);
- clamped_dst = DstLimits::max();
- clamped_dst += SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst);
- clamped_dst = DstLimits::max();
- clamped_dst -= SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst);
- clamped_dst = 0;
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
- if (SrcLimits::is_iec559) {
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
- TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- if (DstLimits::is_integer) {
- if (SrcLimits::digits < DstLimits::digits) {
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
- static_cast<Src>(DstLimits::max()));
- } else {
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
- }
- TEST_EXPECTED_RANGE(
- RANGE_VALID,
- static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest()));
- }
- } 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_VALUE(Src(Src(0) - DstLimits::lowest()),
- ClampDiv(DstLimits::lowest(), 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());
- }
- }
- };
- 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 = 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");
- static_assert(!DstLimits::is_signed, "Destination must be unsigned");
- TestStrictComparison<Dst, Src>(dst, src, line);
- 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());
- TEST_EXPECTED_VALUE(Dst(0), CheckDiv(Dst(0), Src(-1)));
- 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));
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
- }
- };
- 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 = 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.");
- static_assert(!DstLimits::is_signed, "Destination must be unsigned.");
- TestStrictComparison<Dst, Src>(dst, src, line);
- const CheckedNumeric<Dst> checked_dst;
- TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
- TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max());
- TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1));
- TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest());
- 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());
- clamped_dst += SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst);
- clamped_dst = DstLimits::max();
- clamped_dst += SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Overflow(), clamped_dst);
- clamped_dst = DstLimits::max();
- clamped_dst -= SrcLimits::max();
- TEST_EXPECTED_VALUE(DstLimits::Underflow(), clamped_dst);
- clamped_dst = 0;
- 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()));
- EXPECT_EQ(DstLimits::lowest(), saturated_cast<Dst>(SrcLimits::lowest()));
- if (SrcLimits::is_iec559) {
- EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::quiet_NaN()));
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
- TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
- if (DstLimits::is_integer) {
- if (SrcLimits::digits < DstLimits::digits) {
- TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
- static_cast<Src>(DstLimits::max()));
- } else {
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
- }
- TEST_EXPECTED_RANGE(
- RANGE_VALID,
- static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
- TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest()));
- }
- } else {
- TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest());
- }
- }
- };
- 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 = 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.");
- static_assert(DstLimits::is_signed, "Destination must be signed.");
- TestStrictComparison<Dst, Src>(dst, src, line);
- const CheckedNumeric<Dst> checked_dst;
- TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
- 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));
- // Additional saturation tests.
- EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max()));
- EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::lowest()));
- }
- };
- // Helper macro to wrap displaying the conversion types and line numbers
- #define TEST_NUMERIC_CONVERSION(d, s, t) \
- TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__)
- TEST(SafeNumerics, IntMinOperations) {
- TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(int8_t, int16_t, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, uint16_t, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(uint8_t, int16_t, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(int8_t, uint16_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- }
- TEST(SafeNumerics, Int16Operations) {
- TEST_NUMERIC_CONVERSION(int16_t, int16_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(uint16_t, uint16_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(int16_t, int, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uint16_t, unsigned int, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(int16_t, float, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uint16_t, int16_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(uint16_t, int, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uint16_t, intmax_t, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uint16_t, float, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(int16_t, unsigned int,
- UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(int16_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- }
- TEST(SafeNumerics, IntOperations) {
- TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(unsigned int, unsigned int,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(unsigned int, uint8_t,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- }
- TEST(SafeNumerics, IntMaxOperations) {
- TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(intmax_t, unsigned int,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW);
- TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW);
- TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- }
- TEST(SafeNumerics, FloatOperations) {
- TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(float, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(float, unsigned int,
- SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW);
- }
- TEST(SafeNumerics, DoubleOperations) {
- TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(double, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING);
- TEST_NUMERIC_CONVERSION(double, unsigned int,
- SIGN_PRESERVING_VALUE_PRESERVING);
- }
- TEST(SafeNumerics, SizeTOperations) {
- TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
- TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
- }
- // A one-off test to ensure StrictNumeric won't resolve to an incorrect type.
- // If this fails we'll just get a compiler error on an ambiguous overload.
- int TestOverload(int) { // Overload fails.
- return 0;
- }
- uint8_t TestOverload(uint8_t) { // Overload fails.
- return 0;
- }
- size_t TestOverload(size_t) { // Overload succeeds.
- return 0;
- }
- static_assert(
- std::is_same<decltype(TestOverload(StrictNumeric<int>())), int>::value,
- "");
- static_assert(std::is_same<decltype(TestOverload(StrictNumeric<size_t>())),
- size_t>::value,
- "");
- template <typename T>
- struct CastTest1 {
- static constexpr T NaN() { return -1; }
- static constexpr T max() { return numeric_limits<T>::max() - 1; }
- static constexpr T Overflow() { return max(); }
- static constexpr T lowest() { return numeric_limits<T>::lowest() + 1; }
- static constexpr T Underflow() { return lowest(); }
- };
- template <typename T>
- struct CastTest2 {
- static constexpr T NaN() { return 11; }
- static constexpr T max() { return 10; }
- static constexpr T Overflow() { return max(); }
- static constexpr T lowest() { return 1; }
- static constexpr T Underflow() { return lowest(); }
- };
- TEST(SafeNumerics, CastTests) {
- // MSVC catches and warns that we're forcing saturation in these tests.
- // Since that's intentional, we need to shut this warning off.
- #if defined(COMPILER_MSVC)
- #pragma warning(disable : 4756)
- #endif
- int small_positive = 1;
- int small_negative = -1;
- double double_small = 1.0;
- double double_large = numeric_limits<double>::max();
- double double_infinity = numeric_limits<float>::infinity();
- double double_large_int = numeric_limits<int>::max();
- double double_small_int = numeric_limits<int>::lowest();
- // Just test that the casts compile, since the other tests cover logic.
- EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0)));
- EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0)));
- EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0)));
- EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0)));
- EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U)));
- EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U)));
- EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U)));
- EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid());
- EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid());
- EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid());
- EXPECT_TRUE(IsValueNegative(-1));
- EXPECT_TRUE(IsValueNegative(numeric_limits<int>::lowest()));
- EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::lowest()));
- EXPECT_TRUE(IsValueNegative(numeric_limits<double>::lowest()));
- EXPECT_FALSE(IsValueNegative(0));
- EXPECT_FALSE(IsValueNegative(1));
- EXPECT_FALSE(IsValueNegative(0u));
- EXPECT_FALSE(IsValueNegative(1u));
- EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max()));
- EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max()));
- EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max()));
- // These casts and coercions will fail to compile:
- // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0)));
- // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0)));
- // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1));
- // EXPECT_EQ(1, StrictNumeric<size_t>(1U));
- // Test various saturation corner cases.
- EXPECT_EQ(saturated_cast<int>(small_negative),
- static_cast<int>(small_negative));
- EXPECT_EQ(saturated_cast<int>(small_positive),
- static_cast<int>(small_positive));
- EXPECT_EQ(saturated_cast<unsigned>(small_negative), static_cast<unsigned>(0));
- EXPECT_EQ(saturated_cast<int>(double_small), static_cast<int>(double_small));
- EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max());
- EXPECT_EQ(saturated_cast<float>(double_large), double_infinity);
- EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
- EXPECT_EQ(numeric_limits<int>::lowest(),
- saturated_cast<int>(double_small_int));
- EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
- // Test the saturated cast overrides.
- using FloatLimits = numeric_limits<float>;
- using IntLimits = numeric_limits<int>;
- EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(FloatLimits::quiet_NaN())));
- EXPECT_EQ(CastTest1<int>::max(),
- (saturated_cast<int, CastTest1>(FloatLimits::infinity())));
- EXPECT_EQ(CastTest1<int>::max(),
- (saturated_cast<int, CastTest1>(FloatLimits::max())));
- EXPECT_EQ(CastTest1<int>::max(),
- (saturated_cast<int, CastTest1>(float(IntLimits::max()))));
- EXPECT_EQ(CastTest1<int>::lowest(),
- (saturated_cast<int, CastTest1>(-FloatLimits::infinity())));
- EXPECT_EQ(CastTest1<int>::lowest(),
- (saturated_cast<int, CastTest1>(FloatLimits::lowest())));
- EXPECT_EQ(0, (saturated_cast<int, CastTest1>(0.0)));
- EXPECT_EQ(1, (saturated_cast<int, CastTest1>(1.0)));
- EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(-1.0)));
- EXPECT_EQ(0, (saturated_cast<int, CastTest1>(0)));
- EXPECT_EQ(1, (saturated_cast<int, CastTest1>(1)));
- EXPECT_EQ(-1, (saturated_cast<int, CastTest1>(-1)));
- EXPECT_EQ(CastTest1<int>::lowest(),
- (saturated_cast<int, CastTest1>(float(IntLimits::lowest()))));
- EXPECT_EQ(11, (saturated_cast<int, CastTest2>(FloatLimits::quiet_NaN())));
- EXPECT_EQ(10, (saturated_cast<int, CastTest2>(FloatLimits::infinity())));
- EXPECT_EQ(10, (saturated_cast<int, CastTest2>(FloatLimits::max())));
- EXPECT_EQ(1, (saturated_cast<int, CastTest2>(-FloatLimits::infinity())));
- EXPECT_EQ(1, (saturated_cast<int, CastTest2>(FloatLimits::lowest())));
- EXPECT_EQ(1, (saturated_cast<int, CastTest2>(0U)));
- float not_a_number = std::numeric_limits<float>::infinity() -
- std::numeric_limits<float>::infinity();
- EXPECT_TRUE(std::isnan(not_a_number));
- EXPECT_EQ(0, saturated_cast<int>(not_a_number));
- // Test the CheckedNumeric value extractions functions.
- auto int8_min = MakeCheckedNum(numeric_limits<int8_t>::lowest());
- auto int8_max = MakeCheckedNum(numeric_limits<int8_t>::max());
- auto double_max = MakeCheckedNum(numeric_limits<double>::max());
- static_assert(
- std::is_same<int16_t,
- decltype(int8_min.ValueOrDie<int16_t>())::type>::value,
- "ValueOrDie returning incorrect type.");
- static_assert(
- std::is_same<int16_t,
- decltype(int8_min.ValueOrDefault<int16_t>(0))::type>::value,
- "ValueOrDefault returning incorrect type.");
- EXPECT_FALSE(IsValidForType<uint8_t>(int8_min));
- EXPECT_TRUE(IsValidForType<uint8_t>(int8_max));
- EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::lowest()),
- ValueOrDieForType<int>(int8_min));
- EXPECT_TRUE(IsValidForType<uint32_t>(int8_max));
- EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::max()),
- ValueOrDieForType<int>(int8_max));
- EXPECT_EQ(0, ValueOrDefaultForType<int>(double_max, 0));
- uint8_t uint8_dest = 0;
- int16_t int16_dest = 0;
- double double_dest = 0;
- EXPECT_TRUE(int8_max.AssignIfValid(&uint8_dest));
- EXPECT_EQ(static_cast<uint8_t>(numeric_limits<int8_t>::max()), uint8_dest);
- EXPECT_FALSE(int8_min.AssignIfValid(&uint8_dest));
- EXPECT_TRUE(int8_max.AssignIfValid(&int16_dest));
- EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::max()), int16_dest);
- EXPECT_TRUE(int8_min.AssignIfValid(&int16_dest));
- EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::lowest()), int16_dest);
- EXPECT_FALSE(double_max.AssignIfValid(&uint8_dest));
- EXPECT_FALSE(double_max.AssignIfValid(&int16_dest));
- EXPECT_TRUE(double_max.AssignIfValid(&double_dest));
- EXPECT_EQ(numeric_limits<double>::max(), double_dest);
- EXPECT_EQ(1, checked_cast<int>(StrictNumeric<int>(1)));
- EXPECT_EQ(1, saturated_cast<int>(StrictNumeric<int>(1)));
- EXPECT_EQ(1, strict_cast<int>(StrictNumeric<int>(1)));
- enum class EnumTest { kOne = 1 };
- EXPECT_EQ(1, checked_cast<int>(EnumTest::kOne));
- EXPECT_EQ(1, saturated_cast<int>(EnumTest::kOne));
- EXPECT_EQ(1, strict_cast<int>(EnumTest::kOne));
- }
- TEST(SafeNumerics, IsValueInRangeForNumericType) {
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff)));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000)));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001)));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
- std::numeric_limits<int32_t>::lowest()));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
- std::numeric_limits<int64_t>::lowest()));
- // Converting to integer types will discard the fractional part first, so -0.9
- // will be truncated to -0.0.
- EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(-0.9));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1.0));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000)));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff)));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000)));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
- std::numeric_limits<int32_t>::lowest()));
- EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
- static_cast<int64_t>(std::numeric_limits<int32_t>::lowest())));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
- static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()) - 1));
- EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
- std::numeric_limits<int64_t>::lowest()));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff)));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000)));
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001)));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
- std::numeric_limits<int32_t>::lowest()));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1)));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
- std::numeric_limits<int64_t>::lowest()));
- // Converting to integer types will discard the fractional part first, so -0.9
- // will be truncated to -0.0.
- EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(-0.9));
- EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1.0));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000)));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff)));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000)));
- EXPECT_TRUE(
- IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff)));
- EXPECT_TRUE(
- IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff)));
- EXPECT_FALSE(
- IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000)));
- EXPECT_FALSE(
- IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff)));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
- std::numeric_limits<int32_t>::lowest()));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
- static_cast<int64_t>(std::numeric_limits<int32_t>::lowest())));
- EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
- std::numeric_limits<int64_t>::lowest()));
- }
- TEST(SafeNumerics, CompoundNumericOperations) {
- CheckedNumeric<int> a = 1;
- CheckedNumeric<int> b = 2;
- CheckedNumeric<int> c = 3;
- CheckedNumeric<int> d = 4;
- a += b;
- EXPECT_EQ(3, a.ValueOrDie());
- a -= c;
- EXPECT_EQ(0, a.ValueOrDie());
- d /= b;
- EXPECT_EQ(2, d.ValueOrDie());
- d *= d;
- EXPECT_EQ(4, d.ValueOrDie());
- d *= 0.5;
- EXPECT_EQ(2, d.ValueOrDie());
- CheckedNumeric<int> too_large = std::numeric_limits<int>::max();
- EXPECT_TRUE(too_large.IsValid());
- too_large += d;
- EXPECT_FALSE(too_large.IsValid());
- too_large -= d;
- EXPECT_FALSE(too_large.IsValid());
- too_large /= d;
- EXPECT_FALSE(too_large.IsValid());
- }
- TEST(SafeNumerics, VariadicNumericOperations) {
- { // 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);
- }
- }
- TEST(SafeNumerics, CeilInt) {
- constexpr float kMax = static_cast<float>(std::numeric_limits<int>::max());
- constexpr float kMin = std::numeric_limits<int>::min();
- constexpr float kInfinity = std::numeric_limits<float>::infinity();
- constexpr float kNaN = std::numeric_limits<float>::quiet_NaN();
- constexpr int kIntMax = std::numeric_limits<int>::max();
- constexpr int kIntMin = std::numeric_limits<int>::min();
- EXPECT_EQ(kIntMax, ClampCeil(kInfinity));
- EXPECT_EQ(kIntMax, ClampCeil(kMax));
- EXPECT_EQ(kIntMax, ClampCeil(kMax + 100.0f));
- EXPECT_EQ(0, ClampCeil(kNaN));
- EXPECT_EQ(-100, ClampCeil(-100.5f));
- EXPECT_EQ(0, ClampCeil(0.0f));
- EXPECT_EQ(101, ClampCeil(100.5f));
- EXPECT_EQ(kIntMin, ClampCeil(-kInfinity));
- EXPECT_EQ(kIntMin, ClampCeil(kMin));
- EXPECT_EQ(kIntMin, ClampCeil(kMin - 100.0f));
- EXPECT_EQ(0, ClampCeil(-kNaN));
- }
- TEST(SafeNumerics, FloorInt) {
- constexpr float kMax = static_cast<float>(std::numeric_limits<int>::max());
- constexpr float kMin = std::numeric_limits<int>::min();
- constexpr float kInfinity = std::numeric_limits<float>::infinity();
- constexpr float kNaN = std::numeric_limits<float>::quiet_NaN();
- constexpr int kIntMax = std::numeric_limits<int>::max();
- constexpr int kIntMin = std::numeric_limits<int>::min();
- EXPECT_EQ(kIntMax, ClampFloor(kInfinity));
- EXPECT_EQ(kIntMax, ClampFloor(kMax));
- EXPECT_EQ(kIntMax, ClampFloor(kMax + 100.0f));
- EXPECT_EQ(0, ClampFloor(kNaN));
- EXPECT_EQ(-101, ClampFloor(-100.5f));
- EXPECT_EQ(0, ClampFloor(0.0f));
- EXPECT_EQ(100, ClampFloor(100.5f));
- EXPECT_EQ(kIntMin, ClampFloor(-kInfinity));
- EXPECT_EQ(kIntMin, ClampFloor(kMin));
- EXPECT_EQ(kIntMin, ClampFloor(kMin - 100.0f));
- EXPECT_EQ(0, ClampFloor(-kNaN));
- }
- TEST(SafeNumerics, RoundInt) {
- constexpr float kMax = static_cast<float>(std::numeric_limits<int>::max());
- constexpr float kMin = std::numeric_limits<int>::min();
- constexpr float kInfinity = std::numeric_limits<float>::infinity();
- constexpr float kNaN = std::numeric_limits<float>::quiet_NaN();
- constexpr int kIntMax = std::numeric_limits<int>::max();
- constexpr int kIntMin = std::numeric_limits<int>::min();
- EXPECT_EQ(kIntMax, ClampRound(kInfinity));
- EXPECT_EQ(kIntMax, ClampRound(kMax));
- EXPECT_EQ(kIntMax, ClampRound(kMax + 100.0f));
- EXPECT_EQ(0, ClampRound(kNaN));
- EXPECT_EQ(-100, ClampRound(-100.1f));
- EXPECT_EQ(-101, ClampRound(-100.5f));
- EXPECT_EQ(-101, ClampRound(-100.9f));
- EXPECT_EQ(0, ClampRound(0.0f));
- EXPECT_EQ(100, ClampRound(100.1f));
- EXPECT_EQ(101, ClampRound(100.5f));
- EXPECT_EQ(101, ClampRound(100.9f));
- EXPECT_EQ(kIntMin, ClampRound(-kInfinity));
- EXPECT_EQ(kIntMin, ClampRound(kMin));
- EXPECT_EQ(kIntMin, ClampRound(kMin - 100.0f));
- EXPECT_EQ(0, ClampRound(-kNaN));
- }
- TEST(SafeNumerics, Int64) {
- constexpr double kMax =
- static_cast<double>(std::numeric_limits<int64_t>::max());
- constexpr double kMin = std::numeric_limits<int64_t>::min();
- constexpr double kInfinity = std::numeric_limits<double>::infinity();
- constexpr double kNaN = std::numeric_limits<double>::quiet_NaN();
- constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max();
- constexpr int64_t kInt64Min = std::numeric_limits<int64_t>::min();
- EXPECT_EQ(kInt64Max, ClampFloor<int64_t>(kInfinity));
- EXPECT_EQ(kInt64Max, ClampCeil<int64_t>(kInfinity));
- EXPECT_EQ(kInt64Max, ClampRound<int64_t>(kInfinity));
- EXPECT_EQ(kInt64Max, ClampFloor<int64_t>(kMax));
- EXPECT_EQ(kInt64Max, ClampCeil<int64_t>(kMax));
- EXPECT_EQ(kInt64Max, ClampRound<int64_t>(kMax));
- EXPECT_EQ(kInt64Max, ClampFloor<int64_t>(kMax + 100.0));
- EXPECT_EQ(kInt64Max, ClampCeil<int64_t>(kMax + 100.0));
- EXPECT_EQ(kInt64Max, ClampRound<int64_t>(kMax + 100.0));
- EXPECT_EQ(0, ClampFloor<int64_t>(kNaN));
- EXPECT_EQ(0, ClampCeil<int64_t>(kNaN));
- EXPECT_EQ(0, ClampRound<int64_t>(kNaN));
- EXPECT_EQ(kInt64Min, ClampFloor<int64_t>(-kInfinity));
- EXPECT_EQ(kInt64Min, ClampCeil<int64_t>(-kInfinity));
- EXPECT_EQ(kInt64Min, ClampRound<int64_t>(-kInfinity));
- EXPECT_EQ(kInt64Min, ClampFloor<int64_t>(kMin));
- EXPECT_EQ(kInt64Min, ClampCeil<int64_t>(kMin));
- EXPECT_EQ(kInt64Min, ClampRound<int64_t>(kMin));
- EXPECT_EQ(kInt64Min, ClampFloor<int64_t>(kMin - 100.0));
- EXPECT_EQ(kInt64Min, ClampCeil<int64_t>(kMin - 100.0));
- EXPECT_EQ(kInt64Min, ClampRound<int64_t>(kMin - 100.0));
- EXPECT_EQ(0, ClampFloor<int64_t>(-kNaN));
- EXPECT_EQ(0, ClampCeil<int64_t>(-kNaN));
- EXPECT_EQ(0, ClampRound<int64_t>(-kNaN));
- }
- #if defined(__clang__)
- #pragma clang diagnostic pop // -Winteger-overflow
- #endif
- } // namespace internal
- } // namespace base
|