• 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_CONVERSIONS_IMPL_H_
6 #define THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
7 
8 #include <stdint.h>
9 
10 #include <limits>
11 #include <type_traits>
12 
13 #if defined(__GNUC__) || defined(__clang__)
14 #define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
15 #define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
16 #else
17 #define BASE_NUMERICS_LIKELY(x) (x)
18 #define BASE_NUMERICS_UNLIKELY(x) (x)
19 #endif
20 
21 namespace pdfium {
22 namespace base {
23 namespace internal {
24 
25 // The std library doesn't provide a binary max_exponent for integers, however
26 // we can compute an analog using std::numeric_limits<>::digits.
27 template <typename NumericType>
28 struct MaxExponent {
29   static const int value = std::is_floating_point<NumericType>::value
30                                ? std::numeric_limits<NumericType>::max_exponent
31                                : std::numeric_limits<NumericType>::digits + 1;
32 };
33 
34 // The number of bits (including the sign) in an integer. Eliminates sizeof
35 // hacks.
36 template <typename NumericType>
37 struct IntegerBitsPlusSign {
38   static const int value = std::numeric_limits<NumericType>::digits +
39                            std::is_signed<NumericType>::value;
40 };
41 
42 // Helper templates for integer manipulations.
43 
44 template <typename Integer>
45 struct PositionOfSignBit {
46   static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
47 };
48 
49 // Determines if a numeric value is negative without throwing compiler
50 // warnings on: unsigned(value) < 0.
51 template <typename T,
52           typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
IsValueNegative(T value)53 constexpr bool IsValueNegative(T value) {
54   static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
55   return value < 0;
56 }
57 
58 template <typename T,
59           typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
IsValueNegative(T)60 constexpr bool IsValueNegative(T) {
61   static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
62   return false;
63 }
64 
65 // This performs a fast negation, returning a signed value. It works on unsigned
66 // arguments, but probably doesn't do what you want for any unsigned value
67 // larger than max / 2 + 1 (i.e. signed min cast to unsigned).
68 template <typename T>
ConditionalNegate(T x,bool is_negative)69 constexpr typename std::make_signed<T>::type ConditionalNegate(
70     T x,
71     bool is_negative) {
72   static_assert(std::is_integral<T>::value, "Type must be integral");
73   using SignedT = typename std::make_signed<T>::type;
74   using UnsignedT = typename std::make_unsigned<T>::type;
75   return static_cast<SignedT>((static_cast<UnsignedT>(x) ^
76                                static_cast<UnsignedT>(-SignedT(is_negative))) +
77                               is_negative);
78 }
79 
80 // This performs a safe, absolute value via unsigned overflow.
81 template <typename T>
SafeUnsignedAbs(T value)82 constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
83   static_assert(std::is_integral<T>::value, "Type must be integral");
84   using UnsignedT = typename std::make_unsigned<T>::type;
85   return IsValueNegative(value)
86              ? static_cast<UnsignedT>(0u - static_cast<UnsignedT>(value))
87              : static_cast<UnsignedT>(value);
88 }
89 
90 // TODO(jschuh): Switch to std::is_constant_evaluated() once C++20 is supported.
91 // Alternately, the usage could be restructured for "consteval if" in C++23.
92 #define IsConstantEvaluated() (__builtin_is_constant_evaluated())
93 
94 // TODO(jschuh): Debug builds don't reliably propagate constants, so we restrict
95 // some accelerated runtime paths to release builds until this can be forced
96 // with consteval support in C++20 or C++23.
97 #if defined(NDEBUG)
98 constexpr bool kEnableAsmCode = true;
99 #else
100 constexpr bool kEnableAsmCode = false;
101 #endif
102 
103 // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
104 // Also used in a constexpr template to trigger a compilation failure on
105 // an error condition.
106 struct CheckOnFailure {
107   template <typename T>
HandleFailureCheckOnFailure108   static T HandleFailure() {
109 #if defined(_MSC_VER)
110     __debugbreak();
111 #elif defined(__GNUC__) || defined(__clang__)
112     __builtin_trap();
113 #else
114     ((void)(*(volatile char*)0 = 0));
115 #endif
116     return T();
117   }
118 };
119 
120 enum IntegerRepresentation {
121   INTEGER_REPRESENTATION_UNSIGNED,
122   INTEGER_REPRESENTATION_SIGNED
123 };
124 
125 // A range for a given nunmeric Src type is contained for a given numeric Dst
126 // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
127 // numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
128 // We implement this as template specializations rather than simple static
129 // comparisons to ensure type correctness in our comparisons.
130 enum NumericRangeRepresentation {
131   NUMERIC_RANGE_NOT_CONTAINED,
132   NUMERIC_RANGE_CONTAINED
133 };
134 
135 // Helper templates to statically determine if our destination type can contain
136 // maximum and minimum values represented by the source type.
137 
138 template <typename Dst,
139           typename Src,
140           IntegerRepresentation DstSign = std::is_signed<Dst>::value
141                                               ? INTEGER_REPRESENTATION_SIGNED
142                                               : INTEGER_REPRESENTATION_UNSIGNED,
143           IntegerRepresentation SrcSign = std::is_signed<Src>::value
144                                               ? INTEGER_REPRESENTATION_SIGNED
145                                               : INTEGER_REPRESENTATION_UNSIGNED>
146 struct StaticDstRangeRelationToSrcRange;
147 
148 // Same sign: Dst is guaranteed to contain Src only if its range is equal or
149 // larger.
150 template <typename Dst, typename Src, IntegerRepresentation Sign>
151 struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
152   static const NumericRangeRepresentation value =
153       MaxExponent<Dst>::value >= MaxExponent<Src>::value
154           ? NUMERIC_RANGE_CONTAINED
155           : NUMERIC_RANGE_NOT_CONTAINED;
156 };
157 
158 // Unsigned to signed: Dst is guaranteed to contain source only if its range is
159 // larger.
160 template <typename Dst, typename Src>
161 struct StaticDstRangeRelationToSrcRange<Dst,
162                                         Src,
163                                         INTEGER_REPRESENTATION_SIGNED,
164                                         INTEGER_REPRESENTATION_UNSIGNED> {
165   static const NumericRangeRepresentation value =
166       MaxExponent<Dst>::value > MaxExponent<Src>::value
167           ? NUMERIC_RANGE_CONTAINED
168           : NUMERIC_RANGE_NOT_CONTAINED;
169 };
170 
171 // Signed to unsigned: Dst cannot be statically determined to contain Src.
172 template <typename Dst, typename Src>
173 struct StaticDstRangeRelationToSrcRange<Dst,
174                                         Src,
175                                         INTEGER_REPRESENTATION_UNSIGNED,
176                                         INTEGER_REPRESENTATION_SIGNED> {
177   static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
178 };
179 
180 // This class wraps the range constraints as separate booleans so the compiler
181 // can identify constants and eliminate unused code paths.
182 class RangeCheck {
183  public:
184   constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
185       : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
186   constexpr RangeCheck() : is_underflow_(false), is_overflow_(false) {}
187   constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
188   constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
189   constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
190   constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
191   constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
192   constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
193   constexpr bool operator==(const RangeCheck rhs) const {
194     return is_underflow_ == rhs.is_underflow_ &&
195            is_overflow_ == rhs.is_overflow_;
196   }
197   constexpr bool operator!=(const RangeCheck rhs) const {
198     return !(*this == rhs);
199   }
200 
201  private:
202   // Do not change the order of these member variables. The integral conversion
203   // optimization depends on this exact order.
204   const bool is_underflow_;
205   const bool is_overflow_;
206 };
207 
208 // The following helper template addresses a corner case in range checks for
209 // conversion from a floating-point type to an integral type of smaller range
210 // but larger precision (e.g. float -> unsigned). The problem is as follows:
211 //   1. Integral maximum is always one less than a power of two, so it must be
212 //      truncated to fit the mantissa of the floating point. The direction of
213 //      rounding is implementation defined, but by default it's always IEEE
214 //      floats, which round to nearest and thus result in a value of larger
215 //      magnitude than the integral value.
216 //      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
217 //                                   // is 4294967295u.
218 //   2. If the floating point value is equal to the promoted integral maximum
219 //      value, a range check will erroneously pass.
220 //      Example: (4294967296f <= 4294967295u) // This is true due to a precision
221 //                                            // loss in rounding up to float.
222 //   3. When the floating point value is then converted to an integral, the
223 //      resulting value is out of range for the target integral type and
224 //      thus is implementation defined.
225 //      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
226 // To fix this bug we manually truncate the maximum value when the destination
227 // type is an integral of larger precision than the source floating-point type,
228 // such that the resulting maximum is represented exactly as a floating point.
229 template <typename Dst, typename Src, template <typename> class Bounds>
230 struct NarrowingRange {
231   using SrcLimits = std::numeric_limits<Src>;
232   using DstLimits = typename std::numeric_limits<Dst>;
233 
234   // Computes the mask required to make an accurate comparison between types.
235   static const int kShift =
236       (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
237        SrcLimits::digits < DstLimits::digits)
238           ? (DstLimits::digits - SrcLimits::digits)
239           : 0;
240   template <
241       typename T,
242       typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
243 
244   // Masks out the integer bits that are beyond the precision of the
245   // intermediate type used for comparison.
246   static constexpr T Adjust(T value) {
247     static_assert(std::is_same<T, Dst>::value, "");
248     static_assert(kShift < DstLimits::digits, "");
249     using UnsignedDst = typename std::make_unsigned_t<T>;
250     return static_cast<T>(ConditionalNegate(
251         SafeUnsignedAbs(value) & ~((UnsignedDst{1} << kShift) - UnsignedDst{1}),
252         IsValueNegative(value)));
253   }
254 
255   template <typename T,
256             typename std::enable_if<std::is_floating_point<T>::value>::type* =
257                 nullptr>
258   static constexpr T Adjust(T value) {
259     static_assert(std::is_same<T, Dst>::value, "");
260     static_assert(kShift == 0, "");
261     return value;
262   }
263 
264   static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
265   static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
266 };
267 
268 template <typename Dst,
269           typename Src,
270           template <typename>
271           class Bounds,
272           IntegerRepresentation DstSign = std::is_signed<Dst>::value
273                                               ? INTEGER_REPRESENTATION_SIGNED
274                                               : INTEGER_REPRESENTATION_UNSIGNED,
275           IntegerRepresentation SrcSign = std::is_signed<Src>::value
276                                               ? INTEGER_REPRESENTATION_SIGNED
277                                               : INTEGER_REPRESENTATION_UNSIGNED,
278           NumericRangeRepresentation DstRange =
279               StaticDstRangeRelationToSrcRange<Dst, Src>::value>
280 struct DstRangeRelationToSrcRangeImpl;
281 
282 // The following templates are for ranges that must be verified at runtime. We
283 // split it into checks based on signedness to avoid confusing casts and
284 // compiler warnings on signed an unsigned comparisons.
285 
286 // Same sign narrowing: The range is contained for normal limits.
287 template <typename Dst,
288           typename Src,
289           template <typename>
290           class Bounds,
291           IntegerRepresentation DstSign,
292           IntegerRepresentation SrcSign>
293 struct DstRangeRelationToSrcRangeImpl<Dst,
294                                       Src,
295                                       Bounds,
296                                       DstSign,
297                                       SrcSign,
298                                       NUMERIC_RANGE_CONTAINED> {
299   static constexpr RangeCheck Check(Src value) {
300     using SrcLimits = std::numeric_limits<Src>;
301     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
302     return RangeCheck(
303         static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
304             static_cast<Dst>(value) >= DstLimits::lowest(),
305         static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
306             static_cast<Dst>(value) <= DstLimits::max());
307   }
308 };
309 
310 // Signed to signed narrowing: Both the upper and lower boundaries may be
311 // exceeded for standard limits.
312 template <typename Dst, typename Src, template <typename> class Bounds>
313 struct DstRangeRelationToSrcRangeImpl<Dst,
314                                       Src,
315                                       Bounds,
316                                       INTEGER_REPRESENTATION_SIGNED,
317                                       INTEGER_REPRESENTATION_SIGNED,
318                                       NUMERIC_RANGE_NOT_CONTAINED> {
319   static constexpr RangeCheck Check(Src value) {
320     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
321     return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
322   }
323 };
324 
325 // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
326 // standard limits.
327 template <typename Dst, typename Src, template <typename> class Bounds>
328 struct DstRangeRelationToSrcRangeImpl<Dst,
329                                       Src,
330                                       Bounds,
331                                       INTEGER_REPRESENTATION_UNSIGNED,
332                                       INTEGER_REPRESENTATION_UNSIGNED,
333                                       NUMERIC_RANGE_NOT_CONTAINED> {
334   static constexpr RangeCheck Check(Src value) {
335     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
336     return RangeCheck(
337         DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(),
338         value <= DstLimits::max());
339   }
340 };
341 
342 // Unsigned to signed: Only the upper bound can be exceeded for standard limits.
343 template <typename Dst, typename Src, template <typename> class Bounds>
344 struct DstRangeRelationToSrcRangeImpl<Dst,
345                                       Src,
346                                       Bounds,
347                                       INTEGER_REPRESENTATION_SIGNED,
348                                       INTEGER_REPRESENTATION_UNSIGNED,
349                                       NUMERIC_RANGE_NOT_CONTAINED> {
350   static constexpr RangeCheck Check(Src value) {
351     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
352     using Promotion = decltype(Src() + Dst());
353     return RangeCheck(DstLimits::lowest() <= Dst(0) ||
354                           static_cast<Promotion>(value) >=
355                               static_cast<Promotion>(DstLimits::lowest()),
356                       static_cast<Promotion>(value) <=
357                           static_cast<Promotion>(DstLimits::max()));
358   }
359 };
360 
361 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
362 // and any negative value exceeds the lower boundary for standard limits.
363 template <typename Dst, typename Src, template <typename> class Bounds>
364 struct DstRangeRelationToSrcRangeImpl<Dst,
365                                       Src,
366                                       Bounds,
367                                       INTEGER_REPRESENTATION_UNSIGNED,
368                                       INTEGER_REPRESENTATION_SIGNED,
369                                       NUMERIC_RANGE_NOT_CONTAINED> {
370   static constexpr RangeCheck Check(Src value) {
371     using SrcLimits = std::numeric_limits<Src>;
372     using DstLimits = NarrowingRange<Dst, Src, Bounds>;
373     using Promotion = decltype(Src() + Dst());
374     bool ge_zero = false;
375     // Converting floating-point to integer will discard fractional part, so
376     // values in (-1.0, -0.0) will truncate to 0 and fit in Dst.
377     if (std::is_floating_point<Src>::value) {
378       ge_zero = value > Src(-1);
379     } else {
380       ge_zero = value >= Src(0);
381     }
382     return RangeCheck(
383         ge_zero && (DstLimits::lowest() == 0 ||
384                     static_cast<Dst>(value) >= DstLimits::lowest()),
385         static_cast<Promotion>(SrcLimits::max()) <=
386                 static_cast<Promotion>(DstLimits::max()) ||
387             static_cast<Promotion>(value) <=
388                 static_cast<Promotion>(DstLimits::max()));
389   }
390 };
391 
392 // Simple wrapper for statically checking if a type's range is contained.
393 template <typename Dst, typename Src>
394 struct IsTypeInRangeForNumericType {
395   static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
396                             NUMERIC_RANGE_CONTAINED;
397 };
398 
399 template <typename Dst,
400           template <typename> class Bounds = std::numeric_limits,
401           typename Src>
402 constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
403   static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
404   static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
405   static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
406   return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
407 }
408 
409 // Integer promotion templates used by the portable checked integer arithmetic.
410 template <size_t Size, bool IsSigned>
411 struct IntegerForDigitsAndSign;
412 
413 #define INTEGER_FOR_DIGITS_AND_SIGN(I)                          \
414   template <>                                                   \
415   struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
416                                  std::is_signed<I>::value> {    \
417     using type = I;                                             \
418   }
419 
420 INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
421 INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
422 INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
423 INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
424 INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
425 INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
426 INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
427 INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
428 #undef INTEGER_FOR_DIGITS_AND_SIGN
429 
430 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
431 // support 128-bit math, then the ArithmeticPromotion template below will need
432 // to be updated (or more likely replaced with a decltype expression).
433 static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
434               "Max integer size not supported for this toolchain.");
435 
436 template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
437 struct TwiceWiderInteger {
438   using type =
439       typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
440                                        IsSigned>::type;
441 };
442 
443 enum ArithmeticPromotionCategory {
444   LEFT_PROMOTION,  // Use the type of the left-hand argument.
445   RIGHT_PROMOTION  // Use the type of the right-hand argument.
446 };
447 
448 // Determines the type that can represent the largest positive value.
449 template <typename Lhs,
450           typename Rhs,
451           ArithmeticPromotionCategory Promotion =
452               (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
453                   ? LEFT_PROMOTION
454                   : RIGHT_PROMOTION>
455 struct MaxExponentPromotion;
456 
457 template <typename Lhs, typename Rhs>
458 struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
459   using type = Lhs;
460 };
461 
462 template <typename Lhs, typename Rhs>
463 struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
464   using type = Rhs;
465 };
466 
467 // Determines the type that can represent the lowest arithmetic value.
468 template <typename Lhs,
469           typename Rhs,
470           ArithmeticPromotionCategory Promotion =
471               std::is_signed<Lhs>::value
472                   ? (std::is_signed<Rhs>::value
473                          ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
474                                 ? LEFT_PROMOTION
475                                 : RIGHT_PROMOTION)
476                          : LEFT_PROMOTION)
477                   : (std::is_signed<Rhs>::value
478                          ? RIGHT_PROMOTION
479                          : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
480                                 ? LEFT_PROMOTION
481                                 : RIGHT_PROMOTION))>
482 struct LowestValuePromotion;
483 
484 template <typename Lhs, typename Rhs>
485 struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
486   using type = Lhs;
487 };
488 
489 template <typename Lhs, typename Rhs>
490 struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
491   using type = Rhs;
492 };
493 
494 // Determines the type that is best able to represent an arithmetic result.
495 template <
496     typename Lhs,
497     typename Rhs = Lhs,
498     bool is_intmax_type =
499         std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&&
500             IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
501                 value == IntegerBitsPlusSign<intmax_t>::value,
502     bool is_max_exponent =
503         StaticDstRangeRelationToSrcRange<
504             typename MaxExponentPromotion<Lhs, Rhs>::type,
505             Lhs>::value ==
506         NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
507             typename MaxExponentPromotion<Lhs, Rhs>::type,
508             Rhs>::value == NUMERIC_RANGE_CONTAINED>
509 struct BigEnoughPromotion;
510 
511 // The side with the max exponent is big enough.
512 template <typename Lhs, typename Rhs, bool is_intmax_type>
513 struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
514   using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
515   static const bool is_contained = true;
516 };
517 
518 // We can use a twice wider type to fit.
519 template <typename Lhs, typename Rhs>
520 struct BigEnoughPromotion<Lhs, Rhs, false, false> {
521   using type =
522       typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
523                                  std::is_signed<Lhs>::value ||
524                                      std::is_signed<Rhs>::value>::type;
525   static const bool is_contained = true;
526 };
527 
528 // No type is large enough.
529 template <typename Lhs, typename Rhs>
530 struct BigEnoughPromotion<Lhs, Rhs, true, false> {
531   using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
532   static const bool is_contained = false;
533 };
534 
535 // We can statically check if operations on the provided types can wrap, so we
536 // can skip the checked operations if they're not needed. So, for an integer we
537 // care if the destination type preserves the sign and is twice the width of
538 // the source.
539 template <typename T, typename Lhs, typename Rhs = Lhs>
540 struct IsIntegerArithmeticSafe {
541   static const bool value =
542       !std::is_floating_point<T>::value &&
543       !std::is_floating_point<Lhs>::value &&
544       !std::is_floating_point<Rhs>::value &&
545       std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
546       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
547       std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
548       IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
549 };
550 
551 // Promotes to a type that can represent any possible result of a binary
552 // arithmetic operation with the source types.
553 template <typename Lhs,
554           typename Rhs,
555           bool is_promotion_possible = IsIntegerArithmeticSafe<
556               typename std::conditional<std::is_signed<Lhs>::value ||
557                                             std::is_signed<Rhs>::value,
558                                         intmax_t,
559                                         uintmax_t>::type,
560               typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
561 struct FastIntegerArithmeticPromotion;
562 
563 template <typename Lhs, typename Rhs>
564 struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
565   using type =
566       typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
567                                  std::is_signed<Lhs>::value ||
568                                      std::is_signed<Rhs>::value>::type;
569   static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
570   static const bool is_contained = true;
571 };
572 
573 template <typename Lhs, typename Rhs>
574 struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
575   using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
576   static const bool is_contained = false;
577 };
578 
579 // Extracts the underlying type from an enum.
580 template <typename T, bool is_enum = std::is_enum<T>::value>
581 struct ArithmeticOrUnderlyingEnum;
582 
583 template <typename T>
584 struct ArithmeticOrUnderlyingEnum<T, true> {
585   using type = typename std::underlying_type<T>::type;
586   static const bool value = std::is_arithmetic<type>::value;
587 };
588 
589 template <typename T>
590 struct ArithmeticOrUnderlyingEnum<T, false> {
591   using type = T;
592   static const bool value = std::is_arithmetic<type>::value;
593 };
594 
595 // The following are helper templates used in the CheckedNumeric class.
596 template <typename T>
597 class CheckedNumeric;
598 
599 template <typename T>
600 class ClampedNumeric;
601 
602 template <typename T>
603 class StrictNumeric;
604 
605 // Used to treat CheckedNumeric and arithmetic underlying types the same.
606 template <typename T>
607 struct UnderlyingType {
608   using type = typename ArithmeticOrUnderlyingEnum<T>::type;
609   static const bool is_numeric = std::is_arithmetic<type>::value;
610   static const bool is_checked = false;
611   static const bool is_clamped = false;
612   static const bool is_strict = false;
613 };
614 
615 template <typename T>
616 struct UnderlyingType<CheckedNumeric<T>> {
617   using type = T;
618   static const bool is_numeric = true;
619   static const bool is_checked = true;
620   static const bool is_clamped = false;
621   static const bool is_strict = false;
622 };
623 
624 template <typename T>
625 struct UnderlyingType<ClampedNumeric<T>> {
626   using type = T;
627   static const bool is_numeric = true;
628   static const bool is_checked = false;
629   static const bool is_clamped = true;
630   static const bool is_strict = false;
631 };
632 
633 template <typename T>
634 struct UnderlyingType<StrictNumeric<T>> {
635   using type = T;
636   static const bool is_numeric = true;
637   static const bool is_checked = false;
638   static const bool is_clamped = false;
639   static const bool is_strict = true;
640 };
641 
642 template <typename L, typename R>
643 struct IsCheckedOp {
644   static const bool value =
645       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
646       (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
647 };
648 
649 template <typename L, typename R>
650 struct IsClampedOp {
651   static const bool value =
652       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
653       (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
654       !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
655 };
656 
657 template <typename L, typename R>
658 struct IsStrictOp {
659   static const bool value =
660       UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
661       (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
662       !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
663       !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
664 };
665 
666 // as_signed<> returns the supplied integral value (or integral castable
667 // Numeric template) cast as a signed integral of equivalent precision.
668 // I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
669 template <typename Src>
670 constexpr typename std::make_signed<
671     typename base::internal::UnderlyingType<Src>::type>::type
672 as_signed(const Src value) {
673   static_assert(std::is_integral<decltype(as_signed(value))>::value,
674                 "Argument must be a signed or unsigned integer type.");
675   return static_cast<decltype(as_signed(value))>(value);
676 }
677 
678 // as_unsigned<> returns the supplied integral value (or integral castable
679 // Numeric template) cast as an unsigned integral of equivalent precision.
680 // I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
681 template <typename Src>
682 constexpr typename std::make_unsigned<
683     typename base::internal::UnderlyingType<Src>::type>::type
684 as_unsigned(const Src value) {
685   static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
686                 "Argument must be a signed or unsigned integer type.");
687   return static_cast<decltype(as_unsigned(value))>(value);
688 }
689 
690 template <typename L, typename R>
691 constexpr bool IsLessImpl(const L lhs,
692                           const R rhs,
693                           const RangeCheck l_range,
694                           const RangeCheck r_range) {
695   return l_range.IsUnderflow() || r_range.IsOverflow() ||
696          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <
697                                     static_cast<decltype(lhs + rhs)>(rhs));
698 }
699 
700 template <typename L, typename R>
701 struct IsLess {
702   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
703                 "Types must be numeric.");
704   static constexpr bool Test(const L lhs, const R rhs) {
705     return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
706                       DstRangeRelationToSrcRange<L>(rhs));
707   }
708 };
709 
710 template <typename L, typename R>
711 constexpr bool IsLessOrEqualImpl(const L lhs,
712                                  const R rhs,
713                                  const RangeCheck l_range,
714                                  const RangeCheck r_range) {
715   return l_range.IsUnderflow() || r_range.IsOverflow() ||
716          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) <=
717                                     static_cast<decltype(lhs + rhs)>(rhs));
718 }
719 
720 template <typename L, typename R>
721 struct IsLessOrEqual {
722   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
723                 "Types must be numeric.");
724   static constexpr bool Test(const L lhs, const R rhs) {
725     return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
726                              DstRangeRelationToSrcRange<L>(rhs));
727   }
728 };
729 
730 template <typename L, typename R>
731 constexpr bool IsGreaterImpl(const L lhs,
732                              const R rhs,
733                              const RangeCheck l_range,
734                              const RangeCheck r_range) {
735   return l_range.IsOverflow() || r_range.IsUnderflow() ||
736          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >
737                                     static_cast<decltype(lhs + rhs)>(rhs));
738 }
739 
740 template <typename L, typename R>
741 struct IsGreater {
742   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
743                 "Types must be numeric.");
744   static constexpr bool Test(const L lhs, const R rhs) {
745     return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
746                          DstRangeRelationToSrcRange<L>(rhs));
747   }
748 };
749 
750 template <typename L, typename R>
751 constexpr bool IsGreaterOrEqualImpl(const L lhs,
752                                     const R rhs,
753                                     const RangeCheck l_range,
754                                     const RangeCheck r_range) {
755   return l_range.IsOverflow() || r_range.IsUnderflow() ||
756          (l_range == r_range && static_cast<decltype(lhs + rhs)>(lhs) >=
757                                     static_cast<decltype(lhs + rhs)>(rhs));
758 }
759 
760 template <typename L, typename R>
761 struct IsGreaterOrEqual {
762   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
763                 "Types must be numeric.");
764   static constexpr bool Test(const L lhs, const R rhs) {
765     return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
766                                 DstRangeRelationToSrcRange<L>(rhs));
767   }
768 };
769 
770 template <typename L, typename R>
771 struct IsEqual {
772   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
773                 "Types must be numeric.");
774   static constexpr bool Test(const L lhs, const R rhs) {
775     return DstRangeRelationToSrcRange<R>(lhs) ==
776                DstRangeRelationToSrcRange<L>(rhs) &&
777            static_cast<decltype(lhs + rhs)>(lhs) ==
778                static_cast<decltype(lhs + rhs)>(rhs);
779   }
780 };
781 
782 template <typename L, typename R>
783 struct IsNotEqual {
784   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
785                 "Types must be numeric.");
786   static constexpr bool Test(const L lhs, const R rhs) {
787     return DstRangeRelationToSrcRange<R>(lhs) !=
788                DstRangeRelationToSrcRange<L>(rhs) ||
789            static_cast<decltype(lhs + rhs)>(lhs) !=
790                static_cast<decltype(lhs + rhs)>(rhs);
791   }
792 };
793 
794 // These perform the actual math operations on the CheckedNumerics.
795 // Binary arithmetic operations.
796 template <template <typename, typename> class C, typename L, typename R>
797 constexpr bool SafeCompare(const L lhs, const R rhs) {
798   static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
799                 "Types must be numeric.");
800   using Promotion = BigEnoughPromotion<L, R>;
801   using BigType = typename Promotion::type;
802   return Promotion::is_contained
803              // Force to a larger type for speed if both are contained.
804              ? C<BigType, BigType>::Test(
805                    static_cast<BigType>(static_cast<L>(lhs)),
806                    static_cast<BigType>(static_cast<R>(rhs)))
807              // Let the template functions figure it out for mixed types.
808              : C<L, R>::Test(lhs, rhs);
809 }
810 
811 template <typename Dst, typename Src>
812 constexpr bool IsMaxInRangeForNumericType() {
813   return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
814                                           std::numeric_limits<Src>::max());
815 }
816 
817 template <typename Dst, typename Src>
818 constexpr bool IsMinInRangeForNumericType() {
819   return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
820                                        std::numeric_limits<Src>::lowest());
821 }
822 
823 template <typename Dst, typename Src>
824 constexpr Dst CommonMax() {
825   return !IsMaxInRangeForNumericType<Dst, Src>()
826              ? Dst(std::numeric_limits<Dst>::max())
827              : Dst(std::numeric_limits<Src>::max());
828 }
829 
830 template <typename Dst, typename Src>
831 constexpr Dst CommonMin() {
832   return !IsMinInRangeForNumericType<Dst, Src>()
833              ? Dst(std::numeric_limits<Dst>::lowest())
834              : Dst(std::numeric_limits<Src>::lowest());
835 }
836 
837 // This is a wrapper to generate return the max or min for a supplied type.
838 // If the argument is false, the returned value is the maximum. If true the
839 // returned value is the minimum.
840 template <typename Dst, typename Src = Dst>
841 constexpr Dst CommonMaxOrMin(bool is_min) {
842   return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
843 }
844 
845 }  // namespace internal
846 }  // namespace base
847 }  // namespace pdfium
848 
849 #endif  // THIRD_PARTY_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
850