Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
safe_math_shared_impl.h
Go to the documentation of this file.
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 <cassert>
9#include <climits>
10#include <cmath>
11#include <cstddef>
12#include <cstdint>
13#include <cstdlib>
14#include <limits>
15#include <type_traits>
16
19
20#if defined(OS_ASMJS)
21// Optimized safe math instructions are incompatible with asmjs.
22#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
23// Where available use builtin math overflow support on Clang and GCC.
24#elif !defined(__native_client__) && \
25 ((defined(__clang__) && \
26 ((__clang_major__ > 3) || \
27 (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
28 (defined(__GNUC__) && __GNUC__ >= 5))
30#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
31#else
32#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
33#endif
34
35namespace base {
36namespace internal {
37
38// These are the non-functioning boilerplate implementations of the optimized
39// safe math routines.
40#if !BASE_HAS_OPTIMIZED_SAFE_MATH
41template <typename T, typename U>
42struct CheckedAddFastOp {
43 static const bool is_supported = false;
44 template <typename V>
45 static constexpr bool Do(T, U, V*) {
46 // Force a compile failure if instantiated.
47 return CheckOnFailure::template HandleFailure<bool>();
48 }
49};
50
51template <typename T, typename U>
52struct CheckedSubFastOp {
53 static const bool is_supported = false;
54 template <typename V>
55 static constexpr bool Do(T, U, V*) {
56 // Force a compile failure if instantiated.
57 return CheckOnFailure::template HandleFailure<bool>();
58 }
59};
60
61template <typename T, typename U>
62struct CheckedMulFastOp {
63 static const bool is_supported = false;
64 template <typename V>
65 static constexpr bool Do(T, U, V*) {
66 // Force a compile failure if instantiated.
67 return CheckOnFailure::template HandleFailure<bool>();
68 }
69};
70
71template <typename T, typename U>
72struct ClampedAddFastOp {
73 static const bool is_supported = false;
74 template <typename V>
75 static constexpr V Do(T, U) {
76 // Force a compile failure if instantiated.
77 return CheckOnFailure::template HandleFailure<V>();
78 }
79};
80
81template <typename T, typename U>
82struct ClampedSubFastOp {
83 static const bool is_supported = false;
84 template <typename V>
85 static constexpr V Do(T, U) {
86 // Force a compile failure if instantiated.
87 return CheckOnFailure::template HandleFailure<V>();
88 }
89};
90
91template <typename T, typename U>
92struct ClampedMulFastOp {
93 static const bool is_supported = false;
94 template <typename V>
95 static constexpr V Do(T, U) {
96 // Force a compile failure if instantiated.
97 return CheckOnFailure::template HandleFailure<V>();
98 }
99};
100
101template <typename T>
102struct ClampedNegFastOp {
103 static const bool is_supported = false;
104 static constexpr T Do(T) {
105 // Force a compile failure if instantiated.
106 return CheckOnFailure::template HandleFailure<T>();
107 }
108};
109#endif // BASE_HAS_OPTIMIZED_SAFE_MATH
110#undef BASE_HAS_OPTIMIZED_SAFE_MATH
111
112// This is used for UnsignedAbs, where we need to support floating-point
113// template instantiations even though we don't actually support the operations.
114// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
115// so the float versions will not compile.
116template <typename Numeric,
117 bool IsInteger = std::is_integral<Numeric>::value,
118 bool IsFloat = std::is_floating_point<Numeric>::value>
120
121template <typename Numeric>
122struct UnsignedOrFloatForSize<Numeric, true, false> {
123 using type = typename std::make_unsigned<Numeric>::type;
124};
125
126template <typename Numeric>
127struct UnsignedOrFloatForSize<Numeric, false, true> {
128 using type = Numeric;
129};
130
131// Wrap the unary operations to allow SFINAE when instantiating integrals versus
132// floating points. These don't perform any overflow checking. Rather, they
133// exhibit well-defined overflow semantics and rely on the caller to detect
134// if an overflow occurred.
135
136template <typename T,
137 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
138constexpr T NegateWrapper(T value) {
139 using UnsignedT = typename std::make_unsigned<T>::type;
140 // This will compile to a NEG on Intel, and is normal negation on ARM.
141 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
142}
143
144template <
145 typename T,
146 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
147constexpr T NegateWrapper(T value) {
148 return -value;
149}
150
151template <typename T,
152 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
153constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
154 return ~value;
155}
156
157template <typename T,
158 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
159constexpr T AbsWrapper(T value) {
160 return static_cast<T>(SafeUnsignedAbs(value));
161}
162
163template <
164 typename T,
165 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
166constexpr T AbsWrapper(T value) {
167 return value < 0 ? -value : value;
168}
169
170template <template <typename, typename, typename> class M,
171 typename L,
172 typename R>
174 using math = M<typename UnderlyingType<L>::type,
176 void>;
177 using type = typename math::result_type;
178};
179
180// These variadic templates work out the return types.
181// TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
182template <template <typename, typename, typename> class M,
183 typename L,
184 typename R,
185 typename... Args>
186struct ResultType;
187
188template <template <typename, typename, typename> class M,
189 typename L,
190 typename R>
191struct ResultType<M, L, R> {
193};
194
195template <template <typename, typename, typename> class M,
196 typename L,
197 typename R,
198 typename... Args>
203
204// The following macros are just boilerplate for the standard arithmetic
205// operator overloads and variadic function templates. A macro isn't the nicest
206// solution, but it beats rewriting these over and over again.
207#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
208 template <typename L, typename R, typename... Args> \
209 constexpr CLASS##Numeric< \
210 typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
211 CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
212 return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
213 args...); \
214 }
215
216#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
217 /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
218 template <typename L, typename R, \
219 typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* = \
220 nullptr> \
221 constexpr CLASS##Numeric< \
222 typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
223 operator OP(const L lhs, const R rhs) { \
224 return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
225 rhs); \
226 } \
227 /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
228 template <typename L> \
229 template <typename R> \
230 constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP( \
231 const R rhs) { \
232 return MathOp<CLASS##OP_NAME##Op>(rhs); \
233 } \
234 /* Variadic arithmetic functions that return CLASS##Numeric. */ \
235 BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
236
237} // namespace internal
238} // namespace base
239
240#endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
uint8_t value
#define R(r)
T __attribute__((ext_vector_type(N))) V
constexpr T NegateWrapper(T value)
constexpr std::make_unsigned< T >::type SafeUnsignedAbs(T value)
constexpr T AbsWrapper(T value)
constexpr std::make_unsigned< T >::type InvertWrapper(T value)
#define T
#define M(PROC, DITHER)
static constexpr bool Do(T, U, V *)
static constexpr bool Do(T, U, V *)
static constexpr bool Do(T, U, V *)
typename math::result_type type
M< typename UnderlyingType< L >::type, typename UnderlyingType< R >::type, void > math
typename MathWrapper< M, L, R >::type type
typename ResultType< M, typename ResultType< M, L, R >::type, Args... >::type type
typename ArithmeticOrUnderlyingEnum< T >::type type