checked_math_impl.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_NUMERICS_CHECKED_MATH_IMPL_H_
  5. #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <climits>
  9. #include <cmath>
  10. #include <cstdlib>
  11. #include <limits>
  12. #include <type_traits>
  13. #include "base/numerics/safe_conversions.h"
  14. #include "base/numerics/safe_math_shared_impl.h"
  15. namespace base {
  16. namespace internal {
  17. template <typename T>
  18. constexpr bool CheckedAddImpl(T x, T y, T* result) {
  19. static_assert(std::is_integral<T>::value, "Type must be integral");
  20. // Since the value of x+y is undefined if we have a signed type, we compute
  21. // it using the unsigned type of the same size.
  22. using UnsignedDst = typename std::make_unsigned<T>::type;
  23. using SignedDst = typename std::make_signed<T>::type;
  24. const UnsignedDst ux = static_cast<UnsignedDst>(x);
  25. const UnsignedDst uy = static_cast<UnsignedDst>(y);
  26. const UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
  27. // Addition is valid if the sign of (x + y) is equal to either that of x or
  28. // that of y.
  29. if (std::is_signed<T>::value
  30. ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) < 0
  31. : uresult < uy) // Unsigned is either valid or underflow.
  32. return false;
  33. *result = static_cast<T>(uresult);
  34. return true;
  35. }
  36. template <typename T, typename U, class Enable = void>
  37. struct CheckedAddOp {};
  38. template <typename T, typename U>
  39. struct CheckedAddOp<T,
  40. U,
  41. typename std::enable_if<std::is_integral<T>::value &&
  42. std::is_integral<U>::value>::type> {
  43. using result_type = typename MaxExponentPromotion<T, U>::type;
  44. template <typename V>
  45. static constexpr bool Do(T x, U y, V* result) {
  46. if constexpr (CheckedAddFastOp<T, U>::is_supported)
  47. return CheckedAddFastOp<T, U>::Do(x, y, result);
  48. // Double the underlying type up to a full machine word.
  49. using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
  50. using Promotion =
  51. typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
  52. IntegerBitsPlusSign<intptr_t>::value),
  53. typename BigEnoughPromotion<T, U>::type,
  54. FastPromotion>::type;
  55. // Fail if either operand is out of range for the promoted type.
  56. // TODO(jschuh): This could be made to work for a broader range of values.
  57. if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
  58. !IsValueInRangeForNumericType<Promotion>(y))) {
  59. return false;
  60. }
  61. Promotion presult = {};
  62. bool is_valid = true;
  63. if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
  64. presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
  65. } else {
  66. is_valid = CheckedAddImpl(static_cast<Promotion>(x),
  67. static_cast<Promotion>(y), &presult);
  68. }
  69. if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
  70. return false;
  71. *result = static_cast<V>(presult);
  72. return true;
  73. }
  74. };
  75. template <typename T>
  76. constexpr bool CheckedSubImpl(T x, T y, T* result) {
  77. static_assert(std::is_integral<T>::value, "Type must be integral");
  78. // Since the value of x+y is undefined if we have a signed type, we compute
  79. // it using the unsigned type of the same size.
  80. using UnsignedDst = typename std::make_unsigned<T>::type;
  81. using SignedDst = typename std::make_signed<T>::type;
  82. const UnsignedDst ux = static_cast<UnsignedDst>(x);
  83. const UnsignedDst uy = static_cast<UnsignedDst>(y);
  84. const UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
  85. // Subtraction is valid if either x and y have same sign, or (x-y) and x have
  86. // the same sign.
  87. if (std::is_signed<T>::value
  88. ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) < 0
  89. : x < y)
  90. return false;
  91. *result = static_cast<T>(uresult);
  92. return true;
  93. }
  94. template <typename T, typename U, class Enable = void>
  95. struct CheckedSubOp {};
  96. template <typename T, typename U>
  97. struct CheckedSubOp<T,
  98. U,
  99. typename std::enable_if<std::is_integral<T>::value &&
  100. std::is_integral<U>::value>::type> {
  101. using result_type = typename MaxExponentPromotion<T, U>::type;
  102. template <typename V>
  103. static constexpr bool Do(T x, U y, V* result) {
  104. if constexpr (CheckedSubFastOp<T, U>::is_supported)
  105. return CheckedSubFastOp<T, U>::Do(x, y, result);
  106. // Double the underlying type up to a full machine word.
  107. using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
  108. using Promotion =
  109. typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
  110. IntegerBitsPlusSign<intptr_t>::value),
  111. typename BigEnoughPromotion<T, U>::type,
  112. FastPromotion>::type;
  113. // Fail if either operand is out of range for the promoted type.
  114. // TODO(jschuh): This could be made to work for a broader range of values.
  115. if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
  116. !IsValueInRangeForNumericType<Promotion>(y))) {
  117. return false;
  118. }
  119. Promotion presult = {};
  120. bool is_valid = true;
  121. if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
  122. presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
  123. } else {
  124. is_valid = CheckedSubImpl(static_cast<Promotion>(x),
  125. static_cast<Promotion>(y), &presult);
  126. }
  127. if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
  128. return false;
  129. *result = static_cast<V>(presult);
  130. return true;
  131. }
  132. };
  133. template <typename T>
  134. constexpr bool CheckedMulImpl(T x, T y, T* result) {
  135. static_assert(std::is_integral<T>::value, "Type must be integral");
  136. // Since the value of x*y is potentially undefined if we have a signed type,
  137. // we compute it using the unsigned type of the same size.
  138. using UnsignedDst = typename std::make_unsigned<T>::type;
  139. using SignedDst = typename std::make_signed<T>::type;
  140. const UnsignedDst ux = SafeUnsignedAbs(x);
  141. const UnsignedDst uy = SafeUnsignedAbs(y);
  142. const UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
  143. const bool is_negative =
  144. std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
  145. // We have a fast out for unsigned identity or zero on the second operand.
  146. // After that it's an unsigned overflow check on the absolute value, with
  147. // a +1 bound for a negative result.
  148. if (uy > UnsignedDst(!std::is_signed<T>::value || is_negative) &&
  149. ux > (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy)
  150. return false;
  151. *result = static_cast<T>(is_negative ? 0 - uresult : uresult);
  152. return true;
  153. }
  154. template <typename T, typename U, class Enable = void>
  155. struct CheckedMulOp {};
  156. template <typename T, typename U>
  157. struct CheckedMulOp<T,
  158. U,
  159. typename std::enable_if<std::is_integral<T>::value &&
  160. std::is_integral<U>::value>::type> {
  161. using result_type = typename MaxExponentPromotion<T, U>::type;
  162. template <typename V>
  163. static constexpr bool Do(T x, U y, V* result) {
  164. if constexpr (CheckedMulFastOp<T, U>::is_supported)
  165. return CheckedMulFastOp<T, U>::Do(x, y, result);
  166. using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
  167. // Verify the destination type can hold the result (always true for 0).
  168. if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
  169. !IsValueInRangeForNumericType<Promotion>(y)) &&
  170. x && y)) {
  171. return false;
  172. }
  173. Promotion presult = {};
  174. bool is_valid = true;
  175. if (CheckedMulFastOp<Promotion, Promotion>::is_supported) {
  176. // The fast op may be available with the promoted type.
  177. // The casts here are safe because of the "value in range" conditional
  178. // above.
  179. is_valid = CheckedMulFastOp<Promotion, Promotion>::Do(
  180. static_cast<Promotion>(x), static_cast<Promotion>(y), &presult);
  181. } else if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
  182. presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
  183. } else {
  184. is_valid = CheckedMulImpl(static_cast<Promotion>(x),
  185. static_cast<Promotion>(y), &presult);
  186. }
  187. if (!is_valid || !IsValueInRangeForNumericType<V>(presult))
  188. return false;
  189. *result = static_cast<V>(presult);
  190. return true;
  191. }
  192. };
  193. // Division just requires a check for a zero denominator or an invalid negation
  194. // on signed min/-1.
  195. template <typename T, typename U, class Enable = void>
  196. struct CheckedDivOp {};
  197. template <typename T, typename U>
  198. struct CheckedDivOp<T,
  199. U,
  200. typename std::enable_if<std::is_integral<T>::value &&
  201. std::is_integral<U>::value>::type> {
  202. using result_type = typename MaxExponentPromotion<T, U>::type;
  203. template <typename V>
  204. static constexpr bool Do(T x, U y, V* result) {
  205. if (BASE_NUMERICS_UNLIKELY(!y))
  206. return false;
  207. // The overflow check can be compiled away if we don't have the exact
  208. // combination of types needed to trigger this case.
  209. using Promotion = typename BigEnoughPromotion<T, U>::type;
  210. if (BASE_NUMERICS_UNLIKELY(
  211. (std::is_signed<T>::value && std::is_signed<U>::value &&
  212. IsTypeInRangeForNumericType<T, Promotion>::value &&
  213. static_cast<Promotion>(x) ==
  214. std::numeric_limits<Promotion>::lowest() &&
  215. y == static_cast<U>(-1)))) {
  216. return false;
  217. }
  218. // This branch always compiles away if the above branch wasn't removed.
  219. if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
  220. !IsValueInRangeForNumericType<Promotion>(y)) &&
  221. x)) {
  222. return false;
  223. }
  224. const Promotion presult = Promotion(x) / Promotion(y);
  225. if (!IsValueInRangeForNumericType<V>(presult))
  226. return false;
  227. *result = static_cast<V>(presult);
  228. return true;
  229. }
  230. };
  231. template <typename T, typename U, class Enable = void>
  232. struct CheckedModOp {};
  233. template <typename T, typename U>
  234. struct CheckedModOp<T,
  235. U,
  236. typename std::enable_if<std::is_integral<T>::value &&
  237. std::is_integral<U>::value>::type> {
  238. using result_type = typename MaxExponentPromotion<T, U>::type;
  239. template <typename V>
  240. static constexpr bool Do(T x, U y, V* result) {
  241. if (BASE_NUMERICS_UNLIKELY(!y))
  242. return false;
  243. using Promotion = typename BigEnoughPromotion<T, U>::type;
  244. if (BASE_NUMERICS_UNLIKELY(
  245. (std::is_signed<T>::value && std::is_signed<U>::value &&
  246. IsTypeInRangeForNumericType<T, Promotion>::value &&
  247. static_cast<Promotion>(x) ==
  248. std::numeric_limits<Promotion>::lowest() &&
  249. y == static_cast<U>(-1)))) {
  250. *result = 0;
  251. return true;
  252. }
  253. const Promotion presult =
  254. static_cast<Promotion>(x) % static_cast<Promotion>(y);
  255. if (!IsValueInRangeForNumericType<V>(presult))
  256. return false;
  257. *result = static_cast<Promotion>(presult);
  258. return true;
  259. }
  260. };
  261. template <typename T, typename U, class Enable = void>
  262. struct CheckedLshOp {};
  263. // Left shift. Shifts less than 0 or greater than or equal to the number
  264. // of bits in the promoted type are undefined. Shifts of negative values
  265. // are undefined. Otherwise it is defined when the result fits.
  266. template <typename T, typename U>
  267. struct CheckedLshOp<T,
  268. U,
  269. typename std::enable_if<std::is_integral<T>::value &&
  270. std::is_integral<U>::value>::type> {
  271. using result_type = T;
  272. template <typename V>
  273. static constexpr bool Do(T x, U shift, V* result) {
  274. // Disallow negative numbers and verify the shift is in bounds.
  275. if (BASE_NUMERICS_LIKELY(!IsValueNegative(x) &&
  276. as_unsigned(shift) <
  277. as_unsigned(std::numeric_limits<T>::digits))) {
  278. // Shift as unsigned to avoid undefined behavior.
  279. *result = static_cast<V>(as_unsigned(x) << shift);
  280. // If the shift can be reversed, we know it was valid.
  281. return *result >> shift == x;
  282. }
  283. // Handle the legal corner-case of a full-width signed shift of zero.
  284. if (!std::is_signed<T>::value || x ||
  285. as_unsigned(shift) != as_unsigned(std::numeric_limits<T>::digits))
  286. return false;
  287. *result = 0;
  288. return true;
  289. }
  290. };
  291. template <typename T, typename U, class Enable = void>
  292. struct CheckedRshOp {};
  293. // Right shift. Shifts less than 0 or greater than or equal to the number
  294. // of bits in the promoted type are undefined. Otherwise, it is always defined,
  295. // but a right shift of a negative value is implementation-dependent.
  296. template <typename T, typename U>
  297. struct CheckedRshOp<T,
  298. U,
  299. typename std::enable_if<std::is_integral<T>::value &&
  300. std::is_integral<U>::value>::type> {
  301. using result_type = T;
  302. template <typename V>
  303. static constexpr bool Do(T x, U shift, V* result) {
  304. // Use sign conversion to push negative values out of range.
  305. if (BASE_NUMERICS_UNLIKELY(as_unsigned(shift) >=
  306. IntegerBitsPlusSign<T>::value)) {
  307. return false;
  308. }
  309. const T tmp = x >> shift;
  310. if (!IsValueInRangeForNumericType<V>(tmp))
  311. return false;
  312. *result = static_cast<V>(tmp);
  313. return true;
  314. }
  315. };
  316. template <typename T, typename U, class Enable = void>
  317. struct CheckedAndOp {};
  318. // For simplicity we support only unsigned integer results.
  319. template <typename T, typename U>
  320. struct CheckedAndOp<T,
  321. U,
  322. typename std::enable_if<std::is_integral<T>::value &&
  323. std::is_integral<U>::value>::type> {
  324. using result_type = typename std::make_unsigned<
  325. typename MaxExponentPromotion<T, U>::type>::type;
  326. template <typename V>
  327. static constexpr bool Do(T x, U y, V* result) {
  328. const result_type tmp =
  329. static_cast<result_type>(x) & static_cast<result_type>(y);
  330. if (!IsValueInRangeForNumericType<V>(tmp))
  331. return false;
  332. *result = static_cast<V>(tmp);
  333. return true;
  334. }
  335. };
  336. template <typename T, typename U, class Enable = void>
  337. struct CheckedOrOp {};
  338. // For simplicity we support only unsigned integers.
  339. template <typename T, typename U>
  340. struct CheckedOrOp<T,
  341. U,
  342. typename std::enable_if<std::is_integral<T>::value &&
  343. std::is_integral<U>::value>::type> {
  344. using result_type = typename std::make_unsigned<
  345. typename MaxExponentPromotion<T, U>::type>::type;
  346. template <typename V>
  347. static constexpr bool Do(T x, U y, V* result) {
  348. const result_type tmp =
  349. static_cast<result_type>(x) | static_cast<result_type>(y);
  350. if (!IsValueInRangeForNumericType<V>(tmp))
  351. return false;
  352. *result = static_cast<V>(tmp);
  353. return true;
  354. }
  355. };
  356. template <typename T, typename U, class Enable = void>
  357. struct CheckedXorOp {};
  358. // For simplicity we support only unsigned integers.
  359. template <typename T, typename U>
  360. struct CheckedXorOp<T,
  361. U,
  362. typename std::enable_if<std::is_integral<T>::value &&
  363. std::is_integral<U>::value>::type> {
  364. using result_type = typename std::make_unsigned<
  365. typename MaxExponentPromotion<T, U>::type>::type;
  366. template <typename V>
  367. static constexpr bool Do(T x, U y, V* result) {
  368. const result_type tmp =
  369. static_cast<result_type>(x) ^ static_cast<result_type>(y);
  370. if (!IsValueInRangeForNumericType<V>(tmp))
  371. return false;
  372. *result = static_cast<V>(tmp);
  373. return true;
  374. }
  375. };
  376. // Max doesn't really need to be implemented this way because it can't fail,
  377. // but it makes the code much cleaner to use the MathOp wrappers.
  378. template <typename T, typename U, class Enable = void>
  379. struct CheckedMaxOp {};
  380. template <typename T, typename U>
  381. struct CheckedMaxOp<
  382. T,
  383. U,
  384. typename std::enable_if<std::is_arithmetic<T>::value &&
  385. std::is_arithmetic<U>::value>::type> {
  386. using result_type = typename MaxExponentPromotion<T, U>::type;
  387. template <typename V>
  388. static constexpr bool Do(T x, U y, V* result) {
  389. const result_type tmp = IsGreater<T, U>::Test(x, y)
  390. ? static_cast<result_type>(x)
  391. : static_cast<result_type>(y);
  392. if (!IsValueInRangeForNumericType<V>(tmp))
  393. return false;
  394. *result = static_cast<V>(tmp);
  395. return true;
  396. }
  397. };
  398. // Min doesn't really need to be implemented this way because it can't fail,
  399. // but it makes the code much cleaner to use the MathOp wrappers.
  400. template <typename T, typename U, class Enable = void>
  401. struct CheckedMinOp {};
  402. template <typename T, typename U>
  403. struct CheckedMinOp<
  404. T,
  405. U,
  406. typename std::enable_if<std::is_arithmetic<T>::value &&
  407. std::is_arithmetic<U>::value>::type> {
  408. using result_type = typename LowestValuePromotion<T, U>::type;
  409. template <typename V>
  410. static constexpr bool Do(T x, U y, V* result) {
  411. const result_type tmp = IsLess<T, U>::Test(x, y)
  412. ? static_cast<result_type>(x)
  413. : static_cast<result_type>(y);
  414. if (!IsValueInRangeForNumericType<V>(tmp))
  415. return false;
  416. *result = static_cast<V>(tmp);
  417. return true;
  418. }
  419. };
  420. // This is just boilerplate that wraps the standard floating point arithmetic.
  421. // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
  422. #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
  423. template <typename T, typename U> \
  424. struct Checked##NAME##Op< \
  425. T, U, \
  426. typename std::enable_if<std::is_floating_point<T>::value || \
  427. std::is_floating_point<U>::value>::type> { \
  428. using result_type = typename MaxExponentPromotion<T, U>::type; \
  429. template <typename V> \
  430. static constexpr bool Do(T x, U y, V* result) { \
  431. using Promotion = typename MaxExponentPromotion<T, U>::type; \
  432. const Promotion presult = x OP y; \
  433. if (!IsValueInRangeForNumericType<V>(presult)) \
  434. return false; \
  435. *result = static_cast<V>(presult); \
  436. return true; \
  437. } \
  438. };
  439. BASE_FLOAT_ARITHMETIC_OPS(Add, +)
  440. BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
  441. BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
  442. BASE_FLOAT_ARITHMETIC_OPS(Div, /)
  443. #undef BASE_FLOAT_ARITHMETIC_OPS
  444. // Floats carry around their validity state with them, but integers do not. So,
  445. // we wrap the underlying value in a specialization in order to hide that detail
  446. // and expose an interface via accessors.
  447. enum NumericRepresentation {
  448. NUMERIC_INTEGER,
  449. NUMERIC_FLOATING,
  450. NUMERIC_UNKNOWN
  451. };
  452. template <typename NumericType>
  453. struct GetNumericRepresentation {
  454. static const NumericRepresentation value =
  455. std::is_integral<NumericType>::value
  456. ? NUMERIC_INTEGER
  457. : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING
  458. : NUMERIC_UNKNOWN);
  459. };
  460. template <typename T,
  461. NumericRepresentation type = GetNumericRepresentation<T>::value>
  462. class CheckedNumericState {};
  463. // Integrals require quite a bit of additional housekeeping to manage state.
  464. template <typename T>
  465. class CheckedNumericState<T, NUMERIC_INTEGER> {
  466. public:
  467. template <typename Src = int>
  468. constexpr explicit CheckedNumericState(Src value = 0, bool is_valid = true)
  469. : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
  470. value_(WellDefinedConversionOrZero(value, is_valid_)) {
  471. static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
  472. }
  473. template <typename Src>
  474. constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
  475. : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
  476. constexpr bool is_valid() const { return is_valid_; }
  477. constexpr T value() const { return value_; }
  478. private:
  479. // Ensures that a type conversion does not trigger undefined behavior.
  480. template <typename Src>
  481. static constexpr T WellDefinedConversionOrZero(Src value, bool is_valid) {
  482. using SrcType = typename internal::UnderlyingType<Src>::type;
  483. return (std::is_integral<SrcType>::value || is_valid)
  484. ? static_cast<T>(value)
  485. : 0;
  486. }
  487. // is_valid_ precedes value_ because member initializers in the constructors
  488. // are evaluated in field order, and is_valid_ must be read when initializing
  489. // value_.
  490. bool is_valid_;
  491. T value_;
  492. };
  493. // Floating points maintain their own validity, but need translation wrappers.
  494. template <typename T>
  495. class CheckedNumericState<T, NUMERIC_FLOATING> {
  496. public:
  497. template <typename Src = double>
  498. constexpr explicit CheckedNumericState(Src value = 0.0, bool is_valid = true)
  499. : value_(WellDefinedConversionOrNaN(
  500. value,
  501. is_valid && IsValueInRangeForNumericType<T>(value))) {}
  502. template <typename Src>
  503. constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
  504. : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
  505. constexpr bool is_valid() const {
  506. // Written this way because std::isfinite is not reliably constexpr.
  507. return IsConstantEvaluated()
  508. ? value_ <= std::numeric_limits<T>::max() &&
  509. value_ >= std::numeric_limits<T>::lowest()
  510. : std::isfinite(value_);
  511. }
  512. constexpr T value() const { return value_; }
  513. private:
  514. // Ensures that a type conversion does not trigger undefined behavior.
  515. template <typename Src>
  516. static constexpr T WellDefinedConversionOrNaN(Src value, bool is_valid) {
  517. using SrcType = typename internal::UnderlyingType<Src>::type;
  518. return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
  519. NUMERIC_RANGE_CONTAINED ||
  520. is_valid)
  521. ? static_cast<T>(value)
  522. : std::numeric_limits<T>::quiet_NaN();
  523. }
  524. T value_;
  525. };
  526. } // namespace internal
  527. } // namespace base
  528. #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_