• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
6 #define 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 "base/numerics/safe_conversions.h"
19 
20 // Where available use builtin math overflow support on Clang and GCC.
21 #if ((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"
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           bool IsInteger = std::is_integral<Numeric>::value,
114           bool IsFloat = std::is_floating_point<Numeric>::value>
115 struct UnsignedOrFloatForSize;
116 
117 template <typename Numeric>
118 struct UnsignedOrFloatForSize<Numeric, true, false> {
119   using type = typename std::make_unsigned<Numeric>::type;
120 };
121 
122 template <typename Numeric>
123 struct UnsignedOrFloatForSize<Numeric, false, true> {
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           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
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 <
141     typename T,
142     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
143 constexpr T NegateWrapper(T value) {
144   return -value;
145 }
146 
147 template <typename T,
148           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
149 constexpr typename std::make_unsigned<T>::type InvertWrapper(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 T AbsWrapper(T value) {
156   return static_cast<T>(SafeUnsignedAbs(value));
157 }
158 
159 template <
160     typename T,
161     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
162 constexpr T AbsWrapper(T value) {
163   return value < 0 ? -value : value;
164 }
165 
166 template <template <typename, typename, typename> class M,
167           typename L,
168           typename R>
169 struct MathWrapper {
170   using math = M<typename UnderlyingType<L>::type,
171                  typename UnderlyingType<R>::type,
172                  void>;
173   using type = typename math::result_type;
174 };
175 
176 // These variadic templates work out the return types.
177 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
178 template <template <typename, typename, typename> class M,
179           typename L,
180           typename R,
181           typename... Args>
182 struct ResultType;
183 
184 template <template <typename, typename, typename> class M,
185           typename L,
186           typename R>
187 struct ResultType<M, L, R> {
188   using type = typename MathWrapper<M, L, R>::type;
189 };
190 
191 template <template <typename, typename, typename> class M,
192           typename L,
193           typename R,
194           typename... Args>
195 struct ResultType {
196   using type =
197       typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
198 };
199 
200 // The following macros are just boilerplate for the standard arithmetic
201 // operator overloads and variadic function templates. A macro isn't the nicest
202 // solution, but it beats rewriting these over and over again.
203 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)       \
204   template <typename L, typename R, typename... Args>                   \
205   constexpr CLASS##Numeric<                                             \
206       typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type>     \
207       CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) {  \
208     return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
209                                                               args...); \
210   }
211 
212 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
213   /* Binary arithmetic operator for all CLASS##Numeric operations. */          \
214   template <typename L, typename R,                                            \
215             typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* =       \
216                 nullptr>                                                       \
217   constexpr CLASS##Numeric<                                                    \
218       typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>                    \
219   operator OP(const L lhs, const R rhs) {                                      \
220     return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,      \
221                                                                      rhs);     \
222   }                                                                            \
223   /* Assignment arithmetic operator implementation from CLASS##Numeric. */     \
224   template <typename L>                                                        \
225   template <typename R>                                                        \
226   constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(             \
227       const R rhs) {                                                           \
228     return MathOp<CLASS##OP_NAME##Op>(rhs);                                    \
229   }                                                                            \
230   /* Variadic arithmetic functions that return CLASS##Numeric. */              \
231   BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
232 
233 }  // namespace internal
234 }  // namespace base
235 
236 #endif  // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
237