• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 
5 #ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
6 #define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <climits>
12 #include <cmath>
13 #include <cstdlib>
14 #include <limits>
15 #include <type_traits>
16 
17 #include "third_party/base/numerics/safe_conversions.h"
18 
19 namespace pdfium {
20 namespace base {
21 namespace internal {
22 
23 // Everything from here up to the floating point operations is portable C++,
24 // but it may not be fast. This code could be split based on
25 // platform/architecture and replaced with potentially faster implementations.
26 
27 // This is used for UnsignedAbs, where we need to support floating-point
28 // template instantiations even though we don't actually support the operations.
29 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
30 // so the float versions will not compile.
31 template <typename Numeric,
32           bool IsInteger = std::is_integral<Numeric>::value,
33           bool IsFloat = std::is_floating_point<Numeric>::value>
34 struct UnsignedOrFloatForSize;
35 
36 template <typename Numeric>
37 struct UnsignedOrFloatForSize<Numeric, true, false> {
38   using type = typename std::make_unsigned<Numeric>::type;
39 };
40 
41 template <typename Numeric>
42 struct UnsignedOrFloatForSize<Numeric, false, true> {
43   using type = Numeric;
44 };
45 
46 // Probe for builtin math overflow support on Clang and version check on GCC.
47 #if defined(EMSCRIPTEN)
48 // Emscripten Clang reports that it has the builtins, it may be lowered to an
49 // instruction that is unsupported in asm.js
50 #define USE_OVERFLOW_BUILTINS (0)
51 #elif defined(__has_builtin)
52 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
53 #elif defined(__GNUC__)
54 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5)
55 #else
56 #define USE_OVERFLOW_BUILTINS (0)
57 #endif
58 
59 template <typename T>
60 bool CheckedAddImpl(T x, T y, T* result) {
61   static_assert(std::is_integral<T>::value, "Type must be integral");
62   // Since the value of x+y is undefined if we have a signed type, we compute
63   // it using the unsigned type of the same size.
64   using UnsignedDst = typename std::make_unsigned<T>::type;
65   using SignedDst = typename std::make_signed<T>::type;
66   auto ux = static_cast<UnsignedDst>(x);
67   auto uy = static_cast<UnsignedDst>(y);
68   auto uresult = static_cast<UnsignedDst>(ux + uy);
69   *result = static_cast<T>(uresult);
70   // Addition is valid if the sign of (x + y) is equal to either that of x or
71   // that of y.
72   return (std::is_signed<T>::value)
73              ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0
74              : uresult >= uy;  // Unsigned is either valid or underflow.
75 }
76 
77 template <typename T, typename U, class Enable = void>
78 struct CheckedAddOp {};
79 
80 template <typename T, typename U>
81 struct CheckedAddOp<T,
82                     U,
83                     typename std::enable_if<std::is_integral<T>::value &&
84                                             std::is_integral<U>::value>::type> {
85   using result_type = typename MaxExponentPromotion<T, U>::type;
86   template <typename V>
87   static bool Do(T x, U y, V* result) {
88 #if USE_OVERFLOW_BUILTINS
89     return !__builtin_add_overflow(x, y, result);
90 #else
91     using Promotion = typename BigEnoughPromotion<T, U>::type;
92     Promotion presult;
93     // Fail if either operand is out of range for the promoted type.
94     // TODO(jschuh): This could be made to work for a broader range of values.
95     bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
96                     IsValueInRangeForNumericType<Promotion>(y);
97 
98     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
99       presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
100     } else {
101       is_valid &= CheckedAddImpl(static_cast<Promotion>(x),
102                                  static_cast<Promotion>(y), &presult);
103     }
104     *result = static_cast<V>(presult);
105     return is_valid && IsValueInRangeForNumericType<V>(presult);
106 #endif
107   }
108 };
109 
110 template <typename T>
111 bool CheckedSubImpl(T x, T y, T* result) {
112   static_assert(std::is_integral<T>::value, "Type must be integral");
113   // Since the value of x+y is undefined if we have a signed type, we compute
114   // it using the unsigned type of the same size.
115   using UnsignedDst = typename std::make_unsigned<T>::type;
116   using SignedDst = typename std::make_signed<T>::type;
117   auto ux = static_cast<UnsignedDst>(x);
118   auto uy = static_cast<UnsignedDst>(y);
119   auto uresult = static_cast<UnsignedDst>(ux - uy);
120   *result = static_cast<T>(uresult);
121   // Subtraction is valid if either x and y have same sign, or (x-y) and x have
122   // the same sign.
123   return (std::is_signed<T>::value)
124              ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0
125              : x >= y;
126 }
127 
128 template <typename T, typename U, class Enable = void>
129 struct CheckedSubOp {};
130 
131 template <typename T, typename U>
132 struct CheckedSubOp<T,
133                     U,
134                     typename std::enable_if<std::is_integral<T>::value &&
135                                             std::is_integral<U>::value>::type> {
136   using result_type = typename MaxExponentPromotion<T, U>::type;
137   template <typename V>
138   static bool Do(T x, U y, V* result) {
139 #if USE_OVERFLOW_BUILTINS
140     return !__builtin_sub_overflow(x, y, result);
141 #else
142     using Promotion = typename BigEnoughPromotion<T, U>::type;
143     Promotion presult;
144     // Fail if either operand is out of range for the promoted type.
145     // TODO(jschuh): This could be made to work for a broader range of values.
146     bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
147                     IsValueInRangeForNumericType<Promotion>(y);
148 
149     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
150       presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
151     } else {
152       is_valid &= CheckedSubImpl(static_cast<Promotion>(x),
153                                  static_cast<Promotion>(y), &presult);
154     }
155     *result = static_cast<V>(presult);
156     return is_valid && IsValueInRangeForNumericType<V>(presult);
157 #endif
158   }
159 };
160 
161 template <typename T>
162 bool CheckedMulImpl(T x, T y, T* result) {
163   static_assert(std::is_integral<T>::value, "Type must be integral");
164   // Since the value of x*y is potentially undefined if we have a signed type,
165   // we compute it using the unsigned type of the same size.
166   using UnsignedDst = typename std::make_unsigned<T>::type;
167   using SignedDst = typename std::make_signed<T>::type;
168   const UnsignedDst ux = SafeUnsignedAbs(x);
169   const UnsignedDst uy = SafeUnsignedAbs(y);
170   auto uresult = static_cast<UnsignedDst>(ux * uy);
171   const bool is_negative =
172       std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
173   *result = is_negative ? 0 - uresult : uresult;
174   // We have a fast out for unsigned identity or zero on the second operand.
175   // After that it's an unsigned overflow check on the absolute value, with
176   // a +1 bound for a negative result.
177   return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
178          ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
179 }
180 
181 template <typename T, typename U, class Enable = void>
182 struct CheckedMulOp {};
183 
184 template <typename T, typename U>
185 struct CheckedMulOp<T,
186                     U,
187                     typename std::enable_if<std::is_integral<T>::value &&
188                                             std::is_integral<U>::value>::type> {
189   using result_type = typename MaxExponentPromotion<T, U>::type;
190   template <typename V>
191   static bool Do(T x, U y, V* result) {
192 #if USE_OVERFLOW_BUILTINS
193 #if defined(__clang__)
194     // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
195     // support full-width, mixed-sign multiply builtins.
196     // https://crbug.com/613003
197     static const bool kUseMaxInt =
198         // Narrower type than uintptr_t is always safe.
199         std::numeric_limits<__typeof__(x * y)>::digits <
200             std::numeric_limits<intptr_t>::digits ||
201         // Safe for intptr_t and uintptr_t if the sign matches.
202         (IntegerBitsPlusSign<__typeof__(x * y)>::value ==
203              IntegerBitsPlusSign<intptr_t>::value &&
204          std::is_signed<T>::value == std::is_signed<U>::value);
205 #else
206     static const bool kUseMaxInt = true;
207 #endif
208     if (kUseMaxInt)
209       return !__builtin_mul_overflow(x, y, result);
210 #endif
211     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
212     Promotion presult;
213     // Fail if either operand is out of range for the promoted type.
214     // TODO(jschuh): This could be made to work for a broader range of values.
215     bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
216                     IsValueInRangeForNumericType<Promotion>(y);
217 
218     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
219       presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
220     } else {
221       is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
222                                  static_cast<Promotion>(y), &presult);
223     }
224     *result = static_cast<V>(presult);
225     return is_valid && IsValueInRangeForNumericType<V>(presult);
226   }
227 };
228 
229 // Avoid poluting the namespace once we're done with the macro.
230 #undef USE_OVERFLOW_BUILTINS
231 
232 // Division just requires a check for a zero denominator or an invalid negation
233 // on signed min/-1.
234 template <typename T>
235 bool CheckedDivImpl(T x, T y, T* result) {
236   static_assert(std::is_integral<T>::value, "Type must be integral");
237   if (y && (!std::is_signed<T>::value ||
238             x != std::numeric_limits<T>::lowest() || y != static_cast<T>(-1))) {
239     *result = x / y;
240     return true;
241   }
242   return false;
243 }
244 
245 template <typename T, typename U, class Enable = void>
246 struct CheckedDivOp {};
247 
248 template <typename T, typename U>
249 struct CheckedDivOp<T,
250                     U,
251                     typename std::enable_if<std::is_integral<T>::value &&
252                                             std::is_integral<U>::value>::type> {
253   using result_type = typename MaxExponentPromotion<T, U>::type;
254   template <typename V>
255   static bool Do(T x, U y, V* result) {
256     using Promotion = typename BigEnoughPromotion<T, U>::type;
257     Promotion presult;
258     // Fail if either operand is out of range for the promoted type.
259     // TODO(jschuh): This could be made to work for a broader range of values.
260     bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
261                     IsValueInRangeForNumericType<Promotion>(y);
262     is_valid &= CheckedDivImpl(static_cast<Promotion>(x),
263                                static_cast<Promotion>(y), &presult);
264     *result = static_cast<V>(presult);
265     return is_valid && IsValueInRangeForNumericType<V>(presult);
266   }
267 };
268 
269 template <typename T>
270 bool CheckedModImpl(T x, T y, T* result) {
271   static_assert(std::is_integral<T>::value, "Type must be integral");
272   if (y > 0) {
273     *result = static_cast<T>(x % y);
274     return true;
275   }
276   return false;
277 }
278 
279 template <typename T, typename U, class Enable = void>
280 struct CheckedModOp {};
281 
282 template <typename T, typename U>
283 struct CheckedModOp<T,
284                     U,
285                     typename std::enable_if<std::is_integral<T>::value &&
286                                             std::is_integral<U>::value>::type> {
287   using result_type = typename MaxExponentPromotion<T, U>::type;
288   template <typename V>
289   static bool Do(T x, U y, V* result) {
290     using Promotion = typename BigEnoughPromotion<T, U>::type;
291     Promotion presult;
292     bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
293                                    static_cast<Promotion>(y), &presult);
294     *result = static_cast<V>(presult);
295     return is_valid && IsValueInRangeForNumericType<V>(presult);
296   }
297 };
298 
299 template <typename T, typename U, class Enable = void>
300 struct CheckedLshOp {};
301 
302 // Left shift. Shifts less than 0 or greater than or equal to the number
303 // of bits in the promoted type are undefined. Shifts of negative values
304 // are undefined. Otherwise it is defined when the result fits.
305 template <typename T, typename U>
306 struct CheckedLshOp<T,
307                     U,
308                     typename std::enable_if<std::is_integral<T>::value &&
309                                             std::is_integral<U>::value>::type> {
310   using result_type = T;
311   template <typename V>
312   static bool Do(T x, U shift, V* result) {
313     using ShiftType = typename std::make_unsigned<T>::type;
314     static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value;
315     const auto real_shift = static_cast<ShiftType>(shift);
316     // Signed shift is not legal on negative values.
317     if (!IsValueNegative(x) && real_shift < kBitWidth) {
318       // Just use a multiplication because it's easy.
319       // TODO(jschuh): This could probably be made more efficient.
320       if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
321         return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result);
322       return !x;  // Special case zero for a full width signed shift.
323     }
324     return false;
325   }
326 };
327 
328 template <typename T, typename U, class Enable = void>
329 struct CheckedRshOp {};
330 
331 // Right shift. Shifts less than 0 or greater than or equal to the number
332 // of bits in the promoted type are undefined. Otherwise, it is always defined,
333 // but a right shift of a negative value is implementation-dependent.
334 template <typename T, typename U>
335 struct CheckedRshOp<T,
336                     U,
337                     typename std::enable_if<std::is_integral<T>::value &&
338                                             std::is_integral<U>::value>::type> {
339   using result_type = T;
340   template <typename V = result_type>
341   static bool Do(T x, U shift, V* result) {
342     // Use the type conversion push negative values out of range.
343     using ShiftType = typename std::make_unsigned<T>::type;
344     if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) {
345       T tmp = x >> shift;
346       *result = static_cast<V>(tmp);
347       return IsValueInRangeForNumericType<V>(tmp);
348     }
349     return false;
350   }
351 };
352 
353 template <typename T, typename U, class Enable = void>
354 struct CheckedAndOp {};
355 
356 // For simplicity we support only unsigned integer results.
357 template <typename T, typename U>
358 struct CheckedAndOp<T,
359                     U,
360                     typename std::enable_if<std::is_integral<T>::value &&
361                                             std::is_integral<U>::value>::type> {
362   using result_type = typename std::make_unsigned<
363       typename MaxExponentPromotion<T, U>::type>::type;
364   template <typename V = result_type>
365   static bool Do(T x, U y, V* result) {
366     result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y);
367     *result = static_cast<V>(tmp);
368     return IsValueInRangeForNumericType<V>(tmp);
369   }
370 };
371 
372 template <typename T, typename U, class Enable = void>
373 struct CheckedOrOp {};
374 
375 // For simplicity we support only unsigned integers.
376 template <typename T, typename U>
377 struct CheckedOrOp<T,
378                    U,
379                    typename std::enable_if<std::is_integral<T>::value &&
380                                            std::is_integral<U>::value>::type> {
381   using result_type = typename std::make_unsigned<
382       typename MaxExponentPromotion<T, U>::type>::type;
383   template <typename V = result_type>
384   static bool Do(T x, U y, V* result) {
385     result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y);
386     *result = static_cast<V>(tmp);
387     return IsValueInRangeForNumericType<V>(tmp);
388   }
389 };
390 
391 template <typename T, typename U, class Enable = void>
392 struct CheckedXorOp {};
393 
394 // For simplicity we support only unsigned integers.
395 template <typename T, typename U>
396 struct CheckedXorOp<T,
397                     U,
398                     typename std::enable_if<std::is_integral<T>::value &&
399                                             std::is_integral<U>::value>::type> {
400   using result_type = typename std::make_unsigned<
401       typename MaxExponentPromotion<T, U>::type>::type;
402   template <typename V = result_type>
403   static bool Do(T x, U y, V* result) {
404     result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y);
405     *result = static_cast<V>(tmp);
406     return IsValueInRangeForNumericType<V>(tmp);
407   }
408 };
409 
410 // Max doesn't really need to be implemented this way because it can't fail,
411 // but it makes the code much cleaner to use the MathOp wrappers.
412 template <typename T, typename U, class Enable = void>
413 struct CheckedMaxOp {};
414 
415 template <typename T, typename U>
416 struct CheckedMaxOp<
417     T,
418     U,
419     typename std::enable_if<std::is_arithmetic<T>::value &&
420                             std::is_arithmetic<U>::value>::type> {
421   using result_type = typename MaxExponentPromotion<T, U>::type;
422   template <typename V = result_type>
423   static bool Do(T x, U y, V* result) {
424     *result = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x)
425                                           : static_cast<result_type>(y);
426     return true;
427   }
428 };
429 
430 // Min doesn't really need to be implemented this way because it can't fail,
431 // but it makes the code much cleaner to use the MathOp wrappers.
432 template <typename T, typename U, class Enable = void>
433 struct CheckedMinOp {};
434 
435 template <typename T, typename U>
436 struct CheckedMinOp<
437     T,
438     U,
439     typename std::enable_if<std::is_arithmetic<T>::value &&
440                             std::is_arithmetic<U>::value>::type> {
441   using result_type = typename LowestValuePromotion<T, U>::type;
442   template <typename V = result_type>
443   static bool Do(T x, U y, V* result) {
444     *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
445                                        : static_cast<result_type>(y);
446     return true;
447   }
448 };
449 
450 // This is just boilerplate that wraps the standard floating point arithmetic.
451 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
452 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP)                                    \
453   template <typename T, typename U>                                            \
454   struct Checked##NAME##Op<                                                    \
455       T, U, typename std::enable_if<std::is_floating_point<T>::value ||        \
456                                     std::is_floating_point<U>::value>::type> { \
457     using result_type = typename MaxExponentPromotion<T, U>::type;             \
458     template <typename V>                                                      \
459     static bool Do(T x, U y, V* result) {                                      \
460       using Promotion = typename MaxExponentPromotion<T, U>::type;             \
461       Promotion presult = x OP y;                                              \
462       *result = static_cast<V>(presult);                                       \
463       return IsValueInRangeForNumericType<V>(presult);                         \
464     }                                                                          \
465   };
466 
467 BASE_FLOAT_ARITHMETIC_OPS(Add, +)
468 BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
469 BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
470 BASE_FLOAT_ARITHMETIC_OPS(Div, /)
471 
472 #undef BASE_FLOAT_ARITHMETIC_OPS
473 
474 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
475 // floating points. These don't perform any overflow checking. Rather, they
476 // exhibit well-defined overflow semantics and rely on the caller to detect
477 // if an overflow occured.
478 
479 template <typename T,
480           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
481 constexpr T NegateWrapper(T value) {
482   using UnsignedT = typename std::make_unsigned<T>::type;
483   // This will compile to a NEG on Intel, and is normal negation on ARM.
484   return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
485 }
486 
487 template <
488     typename T,
489     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
490 constexpr T NegateWrapper(T value) {
491   return -value;
492 }
493 
494 template <typename T,
495           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
496 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
497   return ~value;
498 }
499 
500 template <typename T,
501           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
502 constexpr T AbsWrapper(T value) {
503   return static_cast<T>(SafeUnsignedAbs(value));
504 }
505 
506 template <
507     typename T,
508     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
509 constexpr T AbsWrapper(T value) {
510   return value < 0 ? -value : value;
511 }
512 
513 // Floats carry around their validity state with them, but integers do not. So,
514 // we wrap the underlying value in a specialization in order to hide that detail
515 // and expose an interface via accessors.
516 enum NumericRepresentation {
517   NUMERIC_INTEGER,
518   NUMERIC_FLOATING,
519   NUMERIC_UNKNOWN
520 };
521 
522 template <typename NumericType>
523 struct GetNumericRepresentation {
524   static const NumericRepresentation value =
525       std::is_integral<NumericType>::value
526           ? NUMERIC_INTEGER
527           : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING
528                                                         : NUMERIC_UNKNOWN);
529 };
530 
531 template <typename T, NumericRepresentation type =
532                           GetNumericRepresentation<T>::value>
533 class CheckedNumericState {};
534 
535 // Integrals require quite a bit of additional housekeeping to manage state.
536 template <typename T>
537 class CheckedNumericState<T, NUMERIC_INTEGER> {
538  private:
539   // is_valid_ precedes value_ because member intializers in the constructors
540   // are evaluated in field order, and is_valid_ must be read when initializing
541   // value_.
542   bool is_valid_;
543   T value_;
544 
545   // Ensures that a type conversion does not trigger undefined behavior.
546   template <typename Src>
547   static constexpr T WellDefinedConversionOrZero(const Src value,
548                                                  const bool is_valid) {
549     using SrcType = typename internal::UnderlyingType<Src>::type;
550     return (std::is_integral<SrcType>::value || is_valid)
551                ? static_cast<T>(value)
552                : static_cast<T>(0);
553   }
554 
555  public:
556   template <typename Src, NumericRepresentation type>
557   friend class CheckedNumericState;
558 
559   constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
560 
561   template <typename Src>
562   constexpr CheckedNumericState(Src value, bool is_valid)
563       : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
564         value_(WellDefinedConversionOrZero(value, is_valid_)) {
565     static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
566   }
567 
568   // Copy constructor.
569   template <typename Src>
570   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
571       : is_valid_(rhs.IsValid()),
572         value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
573 
574   template <typename Src>
575   constexpr explicit CheckedNumericState(Src value)
576       : is_valid_(IsValueInRangeForNumericType<T>(value)),
577         value_(WellDefinedConversionOrZero(value, is_valid_)) {}
578 
579   constexpr bool is_valid() const { return is_valid_; }
580   constexpr T value() const { return value_; }
581 };
582 
583 // Floating points maintain their own validity, but need translation wrappers.
584 template <typename T>
585 class CheckedNumericState<T, NUMERIC_FLOATING> {
586  private:
587   T value_;
588 
589   // Ensures that a type conversion does not trigger undefined behavior.
590   template <typename Src>
591   static constexpr T WellDefinedConversionOrNaN(const Src value,
592                                                 const bool is_valid) {
593     using SrcType = typename internal::UnderlyingType<Src>::type;
594     return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
595                 NUMERIC_RANGE_CONTAINED ||
596             is_valid)
597                ? static_cast<T>(value)
598                : std::numeric_limits<T>::quiet_NaN();
599   }
600 
601  public:
602   template <typename Src, NumericRepresentation type>
603   friend class CheckedNumericState;
604 
605   constexpr CheckedNumericState() : value_(0.0) {}
606 
607   template <typename Src>
608   constexpr CheckedNumericState(Src value, bool is_valid)
609       : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
610 
611   template <typename Src>
612   constexpr explicit CheckedNumericState(Src value)
613       : value_(WellDefinedConversionOrNaN(
614             value,
615             IsValueInRangeForNumericType<T>(value))) {}
616 
617   // Copy constructor.
618   template <typename Src>
619   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
620       : value_(WellDefinedConversionOrNaN(
621             rhs.value(),
622             rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
623 
624   constexpr bool is_valid() const {
625     // Written this way because std::isfinite is not reliably constexpr.
626     // TODO(jschuh): Fix this if the libraries ever get fixed.
627     return value_ <= std::numeric_limits<T>::max() &&
628            value_ >= std::numeric_limits<T>::lowest();
629   }
630   constexpr T value() const { return value_; }
631 };
632 
633 template <template <typename, typename, typename> class M,
634           typename L,
635           typename R>
636 struct MathWrapper {
637   using math = M<typename UnderlyingType<L>::type,
638                  typename UnderlyingType<R>::type,
639                  void>;
640   using type = typename math::result_type;
641 };
642 
643 }  // namespace internal
644 }  // namespace base
645 }  // namespace pdfium
646 
647 #endif  // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
648