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