• 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 #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 #include "build/build_config.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 "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 base {
37 namespace internal {
38 
39 // These are the non-functioning boilerplate implementations of the optimized
40 // safe math routines.
41 #if !BASE_HAS_OPTIMIZED_SAFE_MATH
42 template <typename T, typename U>
43 struct CheckedAddFastOp {
44   static const bool is_supported = false;
45   template <typename V>
DoCheckedAddFastOp46   static constexpr bool Do(T, U, V*) {
47     // Force a compile failure if instantiated.
48     return CheckOnFailure::template HandleFailure<bool>();
49   }
50 };
51 
52 template <typename T, typename U>
53 struct CheckedSubFastOp {
54   static const bool is_supported = false;
55   template <typename V>
DoCheckedSubFastOp56   static constexpr bool Do(T, U, V*) {
57     // Force a compile failure if instantiated.
58     return CheckOnFailure::template HandleFailure<bool>();
59   }
60 };
61 
62 template <typename T, typename U>
63 struct CheckedMulFastOp {
64   static const bool is_supported = false;
65   template <typename V>
DoCheckedMulFastOp66   static constexpr bool Do(T, U, V*) {
67     // Force a compile failure if instantiated.
68     return CheckOnFailure::template HandleFailure<bool>();
69   }
70 };
71 
72 template <typename T, typename U>
73 struct ClampedAddFastOp {
74   static const bool is_supported = false;
75   template <typename V>
DoClampedAddFastOp76   static constexpr V Do(T, U) {
77     // Force a compile failure if instantiated.
78     return CheckOnFailure::template HandleFailure<V>();
79   }
80 };
81 
82 template <typename T, typename U>
83 struct ClampedSubFastOp {
84   static const bool is_supported = false;
85   template <typename V>
DoClampedSubFastOp86   static constexpr V Do(T, U) {
87     // Force a compile failure if instantiated.
88     return CheckOnFailure::template HandleFailure<V>();
89   }
90 };
91 
92 template <typename T, typename U>
93 struct ClampedMulFastOp {
94   static const bool is_supported = false;
95   template <typename V>
DoClampedMulFastOp96   static constexpr V Do(T, U) {
97     // Force a compile failure if instantiated.
98     return CheckOnFailure::template HandleFailure<V>();
99   }
100 };
101 
102 template <typename T>
103 struct ClampedNegFastOp {
104   static const bool is_supported = false;
DoClampedNegFastOp105   static constexpr T Do(T) {
106     // Force a compile failure if instantiated.
107     return CheckOnFailure::template HandleFailure<T>();
108   }
109 };
110 #endif  // BASE_HAS_OPTIMIZED_SAFE_MATH
111 #undef BASE_HAS_OPTIMIZED_SAFE_MATH
112 
113 // This is used for UnsignedAbs, where we need to support floating-point
114 // template instantiations even though we don't actually support the operations.
115 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
116 // so the float versions will not compile.
117 template <typename Numeric,
118           bool IsInteger = std::is_integral<Numeric>::value,
119           bool IsFloat = std::is_floating_point<Numeric>::value>
120 struct UnsignedOrFloatForSize;
121 
122 template <typename Numeric>
123 struct UnsignedOrFloatForSize<Numeric, true, false> {
124   using type = typename std::make_unsigned<Numeric>::type;
125 };
126 
127 template <typename Numeric>
128 struct UnsignedOrFloatForSize<Numeric, false, true> {
129   using type = Numeric;
130 };
131 
132 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
133 // floating points. These don't perform any overflow checking. Rather, they
134 // exhibit well-defined overflow semantics and rely on the caller to detect
135 // if an overflow occurred.
136 
137 template <typename T,
138           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
139 constexpr T NegateWrapper(T value) {
140   using UnsignedT = typename std::make_unsigned<T>::type;
141   // This will compile to a NEG on Intel, and is normal negation on ARM.
142   return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
143 }
144 
145 template <
146     typename T,
147     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
148 constexpr T NegateWrapper(T value) {
149   return -value;
150 }
151 
152 template <typename T,
153           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
154 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
155   return ~value;
156 }
157 
158 template <typename T,
159           typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
160 constexpr T AbsWrapper(T value) {
161   return static_cast<T>(SafeUnsignedAbs(value));
162 }
163 
164 template <
165     typename T,
166     typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
167 constexpr T AbsWrapper(T value) {
168   return value < 0 ? -value : value;
169 }
170 
171 template <template <typename, typename, typename> class M,
172           typename L,
173           typename R>
174 struct MathWrapper {
175   using math = M<typename UnderlyingType<L>::type,
176                  typename UnderlyingType<R>::type,
177                  void>;
178   using type = typename math::result_type;
179 };
180 
181 // The following macros are just boilerplate for the standard arithmetic
182 // operator overloads and variadic function templates. A macro isn't the nicest
183 // solution, but it beats rewriting these over and over again.
184 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)       \
185   template <typename L, typename R, typename... Args>                   \
186   constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs,             \
187                                   const Args... args) {                 \
188     return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
189                                                               args...); \
190   }
191 
192 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
193   /* Binary arithmetic operator for all CLASS##Numeric operations. */          \
194   template <typename L, typename R,                                            \
195             typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* =       \
196                 nullptr>                                                       \
197   constexpr CLASS##Numeric<                                                    \
198       typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>                    \
199   operator OP(const L lhs, const R rhs) {                                      \
200     return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,      \
201                                                                      rhs);     \
202   }                                                                            \
203   /* Assignment arithmetic operator implementation from CLASS##Numeric. */     \
204   template <typename L>                                                        \
205   template <typename R>                                                        \
206   constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(             \
207       const R rhs) {                                                           \
208     return MathOp<CLASS##OP_NAME##Op>(rhs);                                    \
209   }                                                                            \
210   /* Variadic arithmetic functions that return CLASS##Numeric. */              \
211   BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
212 
213 }  // namespace internal
214 }  // namespace base
215 
216 #endif  // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
217