xref: /aosp_15_r20/external/pdfium/third_party/base/numerics/safe_math_shared_impl.h (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
6 #define THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <cassert>
12 #include <climits>
13 #include <cmath>
14 #include <cstdlib>
15 #include <limits>
16 #include <type_traits>
17 
18 #include "build/build_config.h"
19 #include "third_party/base/numerics/safe_conversions.h"
20 
21 #if BUILDFLAG(IS_ASMJS)
22 // Optimized safe math instructions are incompatible with asmjs.
23 #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
24 // Where available use builtin math overflow support on Clang and GCC.
25 #elif !defined(__native_client__) &&                       \
26     ((defined(__clang__) &&                                \
27       ((__clang_major__ > 3) ||                            \
28        (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
29      (defined(__GNUC__) && __GNUC__ >= 5))
30 #include "third_party/base/numerics/safe_math_clang_gcc_impl.h"
31 #define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
32 #else
33 #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
34 #endif
35 
36 namespace pdfium {
37 namespace base {
38 namespace internal {
39 
40 // These are the non-functioning boilerplate implementations of the optimized
41 // safe math routines.
42 #if !BASE_HAS_OPTIMIZED_SAFE_MATH
43 template <typename T, typename U>
44 struct CheckedAddFastOp {
45   static const bool is_supported = false;
46   template <typename V>
DoCheckedAddFastOp47   static constexpr bool Do(T, U, V*) {
48     // Force a compile failure if instantiated.
49     return CheckOnFailure::template HandleFailure<bool>();
50   }
51 };
52 
53 template <typename T, typename U>
54 struct CheckedSubFastOp {
55   static const bool is_supported = false;
56   template <typename V>
DoCheckedSubFastOp57   static constexpr bool Do(T, U, V*) {
58     // Force a compile failure if instantiated.
59     return CheckOnFailure::template HandleFailure<bool>();
60   }
61 };
62 
63 template <typename T, typename U>
64 struct CheckedMulFastOp {
65   static const bool is_supported = false;
66   template <typename V>
DoCheckedMulFastOp67   static constexpr bool Do(T, U, V*) {
68     // Force a compile failure if instantiated.
69     return CheckOnFailure::template HandleFailure<bool>();
70   }
71 };
72 
73 template <typename T, typename U>
74 struct ClampedAddFastOp {
75   static const bool is_supported = false;
76   template <typename V>
DoClampedAddFastOp77   static constexpr V Do(T, U) {
78     // Force a compile failure if instantiated.
79     return CheckOnFailure::template HandleFailure<V>();
80   }
81 };
82 
83 template <typename T, typename U>
84 struct ClampedSubFastOp {
85   static const bool is_supported = false;
86   template <typename V>
DoClampedSubFastOp87   static constexpr V Do(T, U) {
88     // Force a compile failure if instantiated.
89     return CheckOnFailure::template HandleFailure<V>();
90   }
91 };
92 
93 template <typename T, typename U>
94 struct ClampedMulFastOp {
95   static const bool is_supported = false;
96   template <typename V>
DoClampedMulFastOp97   static constexpr V Do(T, U) {
98     // Force a compile failure if instantiated.
99     return CheckOnFailure::template HandleFailure<V>();
100   }
101 };
102 
103 template <typename T>
104 struct ClampedNegFastOp {
105   static const bool is_supported = false;
DoClampedNegFastOp106   static constexpr T Do(T) {
107     // Force a compile failure if instantiated.
108     return CheckOnFailure::template HandleFailure<T>();
109   }
110 };
111 #endif  // BASE_HAS_OPTIMIZED_SAFE_MATH
112 #undef BASE_HAS_OPTIMIZED_SAFE_MATH
113 
114 // This is used for UnsignedAbs, where we need to support floating-point
115 // template instantiations even though we don't actually support the operations.
116 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
117 // so the float versions will not compile.
118 template <typename Numeric,
119           bool IsInteger = std::is_integral<Numeric>::value,
120           bool IsFloat = std::is_floating_point<Numeric>::value>
121 struct UnsignedOrFloatForSize;
122 
123 template <typename Numeric>
124 struct UnsignedOrFloatForSize<Numeric, true, false> {
125   using type = typename std::make_unsigned<Numeric>::type;
126 };
127 
128 template <typename Numeric>
129 struct UnsignedOrFloatForSize<Numeric, false, true> {
130   using type = Numeric;
131 };
132 
133 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
134 // floating points. These don't perform any overflow checking. Rather, they
135 // exhibit well-defined overflow semantics and rely on the caller to detect
136 // if an overflow occurred.
137 
138 template <typename T,
139           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
140 constexpr T NegateWrapper(T value) {
141   using UnsignedT = typename std::make_unsigned<T>::type;
142   // This will compile to a NEG on Intel, and is normal negation on ARM.
143   return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
144 }
145 
146 template <
147     typename T,
148     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
149 constexpr T NegateWrapper(T value) {
150   return -value;
151 }
152 
153 template <typename T,
154           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
155 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
156   return ~value;
157 }
158 
159 template <typename T,
160           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
161 constexpr T AbsWrapper(T value) {
162   return static_cast<T>(SafeUnsignedAbs(value));
163 }
164 
165 template <
166     typename T,
167     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
168 constexpr T AbsWrapper(T value) {
169   return value < 0 ? -value : value;
170 }
171 
172 template <template <typename, typename, typename> class M,
173           typename L,
174           typename R>
175 struct MathWrapper {
176   using math = M<typename UnderlyingType<L>::type,
177                  typename UnderlyingType<R>::type,
178                  void>;
179   using type = typename math::result_type;
180 };
181 
182 // The following macros are just boilerplate for the standard arithmetic
183 // operator overloads and variadic function templates. A macro isn't the nicest
184 // solution, but it beats rewriting these over and over again.
185 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)       \
186   template <typename L, typename R, typename... Args>                   \
187   constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs,             \
188                                   const Args... args) {                 \
189     return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
190                                                               args...); \
191   }
192 
193 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
194   /* Binary arithmetic operator for all CLASS##Numeric operations. */          \
195   template <typename L, typename R,                                            \
196             typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* =       \
197                 nullptr>                                                       \
198   constexpr CLASS##Numeric<                                                    \
199       typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>                    \
200   operator OP(const L lhs, const R rhs) {                                      \
201     return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,      \
202                                                                      rhs);     \
203   }                                                                            \
204   /* Assignment arithmetic operator implementation from CLASS##Numeric. */     \
205   template <typename L>                                                        \
206   template <typename R>                                                        \
207   constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(             \
208       const R rhs) {                                                           \
209     return MathOp<CLASS##OP_NAME##Op>(rhs);                                    \
210   }                                                                            \
211   /* Variadic arithmetic functions that return CLASS##Numeric. */              \
212   BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
213 
214 }  // namespace internal
215 }  // namespace base
216 }  // namespace pdfium
217 
218 #endif  // THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
219