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