checked_math_impl.h 23 KB

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