Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
checked_math.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_CHECKED_MATH_H_
6#define BASE_NUMERICS_CHECKED_MATH_H_
7
8#include <cstddef>
9#include <limits>
10#include <type_traits>
11
13
14namespace base {
15namespace internal {
16
17template <typename T>
19 static_assert(std::is_arithmetic<T>::value,
20 "CheckedNumeric<T>: T must be a numeric type.");
21
22 public:
23 using type = T;
24
25 constexpr CheckedNumeric() = default;
26
27 // Copy constructor.
28 template <typename Src>
29 constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
30 : state_(rhs.state_.value(), rhs.IsValid()) {}
31
32 template <typename Src>
33 friend class CheckedNumeric;
34
35 // This is not an explicit constructor because we implicitly upgrade regular
36 // numerics to CheckedNumerics to make them easier to use.
37 template <typename Src>
38 constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit)
39 : state_(value) {
40 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
41 }
42
43 // This is not an explicit constructor because we want a seamless conversion
44 // from StrictNumeric types.
45 template <typename Src>
46 constexpr CheckedNumeric(
47 StrictNumeric<Src> value) // NOLINT(runtime/explicit)
48 : state_(static_cast<Src>(value)) {}
49
50 // IsValid() - The public API to test if a CheckedNumeric is currently valid.
51 // A range checked destination type can be supplied using the Dst template
52 // parameter.
53 template <typename Dst = T>
54 constexpr bool IsValid() const {
55 return state_.is_valid() &&
56 IsValueInRangeForNumericType<Dst>(state_.value());
57 }
58
59 // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid
60 // and is within the range supported by the destination type. Returns true if
61 // successful and false otherwise.
62 template <typename Dst>
63#if defined(__clang__) || defined(__GNUC__)
64 __attribute__((warn_unused_result))
65#elif defined(_MSC_VER)
66 _Check_return_
67#endif
68 constexpr bool
69 AssignIfValid(Dst* result) const {
70 return BASE_NUMERICS_LIKELY(IsValid<Dst>())
71 ? ((*result = static_cast<Dst>(state_.value())), true)
72 : false;
73 }
74
75 // ValueOrDie() - The primary accessor for the underlying value. If the
76 // current state is not valid it will CHECK and crash.
77 // A range checked destination type can be supplied using the Dst template
78 // parameter, which will trigger a CHECK if the value is not in bounds for
79 // the destination.
80 // The CHECK behavior can be overridden by supplying a handler as a
81 // template parameter, for test code, etc. However, the handler cannot access
82 // the underlying value, and it is not available through other means.
83 template <typename Dst = T, class CheckHandler = CheckOnFailure>
84 constexpr StrictNumeric<Dst> ValueOrDie() const {
85 return BASE_NUMERICS_LIKELY(IsValid<Dst>())
86 ? static_cast<Dst>(state_.value())
87 : CheckHandler::template HandleFailure<Dst>();
88 }
89
90 // ValueOrDefault(T default_value) - A convenience method that returns the
91 // current value if the state is valid, and the supplied default_value for
92 // any other state.
93 // A range checked destination type can be supplied using the Dst template
94 // parameter. WARNING: This function may fail to compile or CHECK at runtime
95 // if the supplied default_value is not within range of the destination type.
96 template <typename Dst = T, typename Src>
97 constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const {
98 return BASE_NUMERICS_LIKELY(IsValid<Dst>())
99 ? static_cast<Dst>(state_.value())
100 : checked_cast<Dst>(default_value);
101 }
102
103 // Returns a checked numeric of the specified type, cast from the current
104 // CheckedNumeric. If the current state is invalid or the destination cannot
105 // represent the result then the returned CheckedNumeric will be invalid.
106 template <typename Dst>
108 return *this;
109 }
110
111 // This friend method is available solely for providing more detailed logging
112 // in the tests. Do not implement it in production code, because the
113 // underlying values may change at any time.
114 template <typename U>
116
117 // Prototypes for the supported arithmetic operator overloads.
118 template <typename Src>
119 constexpr CheckedNumeric& operator+=(const Src rhs);
120 template <typename Src>
121 constexpr CheckedNumeric& operator-=(const Src rhs);
122 template <typename Src>
123 constexpr CheckedNumeric& operator*=(const Src rhs);
124 template <typename Src>
125 constexpr CheckedNumeric& operator/=(const Src rhs);
126 template <typename Src>
127 constexpr CheckedNumeric& operator%=(const Src rhs);
128 template <typename Src>
129 constexpr CheckedNumeric& operator<<=(const Src rhs);
130 template <typename Src>
131 constexpr CheckedNumeric& operator>>=(const Src rhs);
132 template <typename Src>
133 constexpr CheckedNumeric& operator&=(const Src rhs);
134 template <typename Src>
135 constexpr CheckedNumeric& operator|=(const Src rhs);
136 template <typename Src>
137 constexpr CheckedNumeric& operator^=(const Src rhs);
138
139 constexpr CheckedNumeric operator-() const {
140 // The negation of two's complement int min is int min, so we simply
141 // check for that in the constexpr case.
142 // We use an optimized code path for a known run-time variable.
143 return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value ||
144 std::is_floating_point<T>::value
146 NegateWrapper(state_.value()),
147 IsValid() && (!std::is_signed<T>::value ||
148 std::is_floating_point<T>::value ||
149 NegateWrapper(state_.value()) !=
150 std::numeric_limits<T>::lowest()))
151 : FastRuntimeNegate();
152 }
153
154 constexpr CheckedNumeric operator~() const {
156 InvertWrapper(state_.value()), IsValid());
157 }
158
159 constexpr CheckedNumeric Abs() const {
160 return !IsValueNegative(state_.value()) ? *this : -*this;
161 }
162
163 template <typename U>
165 const U rhs) const {
166 using R = typename UnderlyingType<U>::type;
167 using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
168 // TODO(jschuh): This can be converted to the MathOp version and remain
169 // constexpr once we have C++14 support.
171 static_cast<result_type>(
172 IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
173 ? state_.value()
174 : Wrapper<U>::value(rhs)),
175 state_.is_valid() && Wrapper<U>::is_valid(rhs));
176 }
177
178 template <typename U>
180 const U rhs) const {
181 using R = typename UnderlyingType<U>::type;
182 using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
183 // TODO(jschuh): This can be converted to the MathOp version and remain
184 // constexpr once we have C++14 support.
186 static_cast<result_type>(
187 IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
188 ? state_.value()
189 : Wrapper<U>::value(rhs)),
190 state_.is_valid() && Wrapper<U>::is_valid(rhs));
191 }
192
193 // This function is available only for integral types. It returns an unsigned
194 // integer of the same width as the source type, containing the absolute value
195 // of the source, and properly handling signed min.
197 UnsignedAbs() const {
199 SafeUnsignedAbs(state_.value()), state_.is_valid());
200 }
201
203 *this += 1;
204 return *this;
205 }
206
207 constexpr CheckedNumeric operator++(int) {
208 CheckedNumeric value = *this;
209 *this += 1;
210 return value;
211 }
212
214 *this -= 1;
215 return *this;
216 }
217
218 constexpr CheckedNumeric operator--(int) {
219 CheckedNumeric value = *this;
220 *this -= 1;
221 return value;
222 }
223
224 // These perform the actual math operations on the CheckedNumerics.
225 // Binary arithmetic operations.
226 template <template <typename, typename, typename> class M,
227 typename L,
228 typename R>
229 static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
230 using Math = typename MathWrapper<M, L, R>::math;
231 T result = 0;
232 bool is_valid =
233 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
234 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
236 }
237
238 // Assignment arithmetic operations.
239 template <template <typename, typename, typename> class M, typename R>
240 constexpr CheckedNumeric& MathOp(const R rhs) {
241 using Math = typename MathWrapper<M, T, R>::math;
242 T result = 0; // Using T as the destination saves a range check.
243 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
244 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
246 return *this;
247 }
248
249 private:
251
252 CheckedNumeric FastRuntimeNegate() const {
253 T result;
254 bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
255 return CheckedNumeric<T>(result, IsValid() && success);
256 }
257
258 template <typename Src>
259 constexpr CheckedNumeric(Src value, bool is_valid)
260 : state_(value, is_valid) {}
261
262 // These wrappers allow us to handle state the same way for both
263 // CheckedNumeric and POD arithmetic types.
264 template <typename Src>
265 struct Wrapper {
266 static constexpr bool is_valid(Src) { return true; }
267 static constexpr Src value(Src value) { return value; }
268 };
269
270 template <typename Src>
271 struct Wrapper<CheckedNumeric<Src>> {
272 static constexpr bool is_valid(const CheckedNumeric<Src> v) {
273 return v.IsValid();
274 }
275 static constexpr Src value(const CheckedNumeric<Src> v) {
276 return v.state_.value();
277 }
278 };
279
280 template <typename Src>
281 struct Wrapper<StrictNumeric<Src>> {
282 static constexpr bool is_valid(const StrictNumeric<Src>) { return true; }
283 static constexpr Src value(const StrictNumeric<Src> v) {
284 return static_cast<Src>(v);
285 }
286 };
287};
288
289// Convenience functions to avoid the ugly template disambiguator syntax.
290template <typename Dst, typename Src>
291constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
292 return value.template IsValid<Dst>();
293}
294
295template <typename Dst, typename Src>
297 const CheckedNumeric<Src> value) {
298 return value.template ValueOrDie<Dst>();
299}
300
301template <typename Dst, typename Src, typename Default>
303 const CheckedNumeric<Src> value,
304 const Default default_value) {
305 return value.template ValueOrDefault<Dst>(default_value);
306}
307
308// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
309// or CheckedNumericType.
310template <typename T>
312 const T value) {
313 return value;
314}
315
316// These implement the variadic wrapper for the math operations.
317template <template <typename, typename, typename> class M,
318 typename L,
319 typename R>
321 const L lhs,
322 const R rhs) {
323 using Math = typename MathWrapper<M, L, R>::math;
325 rhs);
326}
327
328// General purpose wrapper template for arithmetic operations.
329template <template <typename, typename, typename> class M,
330 typename L,
331 typename R,
332 typename... Args>
333constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
334CheckMathOp(const L lhs, const R rhs, const Args... args) {
335 return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...);
336}
337
338BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=)
339BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=)
340BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=)
341BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=)
342BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=)
343BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=)
344BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=)
345BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=)
346BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=)
347BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=)
348BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max)
349BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min)
350
351// These are some extra StrictNumeric operators to support simple pointer
352// arithmetic with our result types. Since wrapping on a pointer is always
353// bad, we trigger the CHECK condition here.
354template <typename L, typename R>
355L* operator+(L* lhs, const StrictNumeric<R> rhs) {
356 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
357 CheckMul(sizeof(L), static_cast<R>(rhs)))
358 .template ValueOrDie<uintptr_t>();
359 return reinterpret_cast<L*>(result);
360}
361
362template <typename L, typename R>
363L* operator-(L* lhs, const StrictNumeric<R> rhs) {
364 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
365 CheckMul(sizeof(L), static_cast<R>(rhs)))
366 .template ValueOrDie<uintptr_t>();
367 return reinterpret_cast<L*>(result);
368}
369
370} // namespace internal
371
372using internal::CheckAdd;
373using internal::CheckAnd;
374using internal::CheckDiv;
375using internal::CheckedNumeric;
376using internal::CheckLsh;
377using internal::CheckMax;
378using internal::CheckMin;
379using internal::CheckMod;
380using internal::CheckMul;
381using internal::CheckOr;
382using internal::CheckRsh;
383using internal::CheckSub;
384using internal::CheckXor;
389
390} // namespace base
391
392#endif // BASE_NUMERICS_CHECKED_MATH_H_
static bool is_valid(SkISize dim)
constexpr CheckedNumeric(StrictNumeric< Src > value)
constexpr CheckedNumeric & operator*=(const Src rhs)
constexpr CheckedNumeric(const CheckedNumeric< Src > &rhs)
constexpr CheckedNumeric & operator&=(const Src rhs)
constexpr StrictNumeric< Dst > ValueOrDie() const
static constexpr CheckedNumeric MathOp(const L lhs, const R rhs)
constexpr CheckedNumeric operator++(int)
constexpr StrictNumeric< Dst > ValueOrDefault(const Src default_value) const
constexpr CheckedNumeric< typename MathWrapper< CheckedMaxOp, T, U >::type > Max(const U rhs) const
constexpr bool AssignIfValid(Dst *result) const
constexpr CheckedNumeric & operator|=(const Src rhs)
constexpr CheckedNumeric operator-() const
constexpr CheckedNumeric & operator--()
constexpr CheckedNumeric operator--(int)
constexpr CheckedNumeric & operator/=(const Src rhs)
constexpr CheckedNumeric & operator-=(const Src rhs)
constexpr CheckedNumeric< typename UnderlyingType< Dst >::type > Cast() const
constexpr CheckedNumeric & MathOp(const R rhs)
constexpr bool IsValid() const
constexpr CheckedNumeric()=default
constexpr CheckedNumeric(Src value)
constexpr CheckedNumeric & operator<<=(const Src rhs)
constexpr CheckedNumeric< typename UnsignedOrFloatForSize< T >::type > UnsignedAbs() const
constexpr CheckedNumeric & operator>>=(const Src rhs)
friend U GetNumericValueForTest(const CheckedNumeric< U > &src)
constexpr CheckedNumeric & operator^=(const Src rhs)
constexpr CheckedNumeric Abs() const
constexpr CheckedNumeric & operator+=(const Src rhs)
constexpr CheckedNumeric operator~() const
constexpr CheckedNumeric & operator++()
constexpr CheckedNumeric & operator%=(const Src rhs)
constexpr CheckedNumeric< typename MathWrapper< CheckedMinOp, T, U >::type > Min(const U rhs) const
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
#define R(r)
__attribute__((visibility("default"))) int RunBenchmarks(int argc
constexpr T NegateWrapper(T value)
constexpr bool IsValueNegative(T value)
constexpr CheckedNumeric< typename MathWrapper< M, L, R >::type > CheckMathOp(const L lhs, const R rhs)
constexpr std::make_unsigned< T >::type SafeUnsignedAbs(T value)
constexpr bool IsValidForType(const CheckedNumeric< Src > value)
constexpr CheckedNumeric< typename UnderlyingType< T >::type > MakeCheckedNum(const T value)
constexpr StrictNumeric< Dst > ValueOrDefaultForType(const CheckedNumeric< Src > value, const Default default_value)
L * operator-(L *lhs, const StrictNumeric< R > rhs)
constexpr StrictNumeric< Dst > ValueOrDieForType(const CheckedNumeric< Src > value)
constexpr std::make_unsigned< T >::type InvertWrapper(T value)
constexpr bool MustTreatAsConstexpr(const T v)
#define T
#define BASE_NUMERICS_LIKELY(x)
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP)
#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
#define M(PROC, DITHER)
typename math::result_type type
M< typename UnderlyingType< L >::type, typename UnderlyingType< R >::type, void > math
typename ArithmeticOrUnderlyingEnum< T >::type type