Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: base/numerics/safe_math.h

Issue 2545253002: Add support for CheckedNumeric Max and Min constexpr functions (Closed)
Patch Set: MakeStrictNum Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_math_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_
6 #define BASE_NUMERICS_SAFE_MATH_H_ 6 #define BASE_NUMERICS_SAFE_MATH_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <limits> 10 #include <limits>
(...skipping 19 matching lines...) Expand all
30 // CheckAdd() - Addition. 30 // CheckAdd() - Addition.
31 // CheckSub() - Subtraction. 31 // CheckSub() - Subtraction.
32 // CheckMul() - Multiplication. 32 // CheckMul() - Multiplication.
33 // CheckDiv() - Division. 33 // CheckDiv() - Division.
34 // CheckMod() - Modulous (integer only). 34 // CheckMod() - Modulous (integer only).
35 // CheckLsh() - Left integer shift (integer only). 35 // CheckLsh() - Left integer shift (integer only).
36 // CheckRsh() - Right integer shift (integer only). 36 // CheckRsh() - Right integer shift (integer only).
37 // CheckAnd() - Bitwise AND (integer only with unsigned result). 37 // CheckAnd() - Bitwise AND (integer only with unsigned result).
38 // CheckOr() - Bitwise OR (integer only with unsigned result). 38 // CheckOr() - Bitwise OR (integer only with unsigned result).
39 // CheckXor() - Bitwise XOR (integer only with unsigned result). 39 // CheckXor() - Bitwise XOR (integer only with unsigned result).
40 // CheckMax() - Maximum of supplied arguments.
41 // CheckMin() - Minimum of supplied arguments.
40 // 42 //
41 // The unary negation, increment, and decrement operators are supported, along 43 // The unary negation, increment, and decrement operators are supported, along
42 // with the following unary arithmetic methods, which return a new 44 // with the following unary arithmetic methods, which return a new
43 // CheckedNumeric as a result of the operation: 45 // CheckedNumeric as a result of the operation:
44 // Abs() - Absolute value. 46 // Abs() - Absolute value.
45 // UnsignedAbs() - Absolute value as an equival-width unsigned underlying type 47 // UnsignedAbs() - Absolute value as an equal-width unsigned underlying type
46 // (valid for only integral types). 48 // (valid for only integral types).
49 // Max() - Returns whichever is greater of the current instance or argument.
50 // The underlying return type is whichever has the greatest magnitude.
51 // Min() - Returns whichever is lowest of the current instance or argument.
52 // The underlying return type is whichever has can represent the lowest
53 // number in the smallest width (e.g. int8_t over unsigned, int over
54 // int8_t, and float over int).
47 // 55 //
48 // The following methods convert from CheckedNumeric to standard numeric values: 56 // The following methods convert from CheckedNumeric to standard numeric values:
49 // AssignIfValid() - Assigns the underlying value to the supplied destination 57 // AssignIfValid() - Assigns the underlying value to the supplied destination
50 // pointer if the value is currently valid and within the range 58 // pointer if the value is currently valid and within the range
51 // supported by the destination type. Returns true on success. 59 // supported by the destination type. Returns true on success.
52 // **************************************************************************** 60 // ****************************************************************************
53 // * WARNING: All of the following functions return a StrictNumeric, which * 61 // * WARNING: All of the following functions return a StrictNumeric, which *
54 // * is valid for comparison and assignment operations, but will trigger a * 62 // * is valid for comparison and assignment operations, but will trigger a *
55 // * compile failure on attempts to assign to a type of insufficient range. * 63 // * compile failure on attempts to assign to a type of insufficient range. *
56 // **************************************************************************** 64 // ****************************************************************************
57 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has 65 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has
58 // has not wrapped and is not the result of an invalid conversion). 66 // has not wrapped and is not the result of an invalid conversion).
59 // ValueOrDie() - Returns the underlying value. If the state is not valid this 67 // ValueOrDie() - Returns the underlying value. If the state is not valid this
60 // call will crash on a CHECK. 68 // call will crash on a CHECK.
61 // ValueOrDefault() - Returns the current value, or the supplied default if the 69 // ValueOrDefault() - Returns the current value, or the supplied default if the
62 // state is not valid (will not trigger a CHECK). 70 // state is not valid (will not trigger a CHECK).
63 // 71 //
64 // The following wrapper functions can be used to avoid the template 72 // The following wrapper functions can be used to avoid the template
65 // disambiguator syntax when converting a destination type. 73 // disambiguator syntax when converting a destination type.
66 // IsValidForType<>() in place of: a.template IsValid<Dst>() 74 // IsValidForType<>() in place of: a.template IsValid<Dst>()
67 // ValueOrDieForType<>() in place of: a.template ValueOrDie() 75 // ValueOrDieForType<>() in place of: a.template ValueOrDie()
68 // ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default) 76 // ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default)
69 // 77 //
70 // The following are general utility methods that are useful for converting 78 // The following are general utility methods that are useful for converting
71 // between arithmetic types and CheckedNumeric types: 79 // between arithmetic types and CheckedNumeric types:
72 // CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric 80 // CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric
73 // derived from casting the current instance to a CheckedNumeric of 81 // derived from casting the current instance to a CheckedNumeric of
74 // the supplied destination type. 82 // the supplied destination type.
75 // CheckNum() - Creates a new CheckedNumeric from the underlying type of the 83 // CheckNum() - Creates a new CheckedNumeric from the underlying type of the
76 // supplied arithmetic or CheckedNumeric type. 84 // supplied arithmetic, CheckedNumeric, or StrictNumeric type.
77 // 85 //
78 // Comparison operations are explicitly not supported because they could result 86 // Comparison operations are explicitly not supported because they could result
79 // in a crash on an unexpected CHECK condition. You should use patterns like the 87 // in a crash on an unexpected CHECK condition. You should use patterns like the
80 // following for comparisons: 88 // following for comparisons:
81 // CheckedNumeric<size_t> checked_size = untrusted_input_value; 89 // CheckedNumeric<size_t> checked_size = untrusted_input_value;
82 // checked_size += HEADER LENGTH; 90 // checked_size += HEADER LENGTH;
83 // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) 91 // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
84 // Do stuff... 92 // Do stuff...
85 93
86 template <typename T> 94 template <typename T>
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 } 221 }
214 222
215 CheckedNumeric Abs() const { 223 CheckedNumeric Abs() const {
216 // Absolute value is always valid for floating point. 224 // Absolute value is always valid for floating point.
217 T value = 0; 225 T value = 0;
218 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && 226 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) &&
219 CheckedAbs(state_.value(), &value); 227 CheckedAbs(state_.value(), &value);
220 return CheckedNumeric<T>(value, is_valid); 228 return CheckedNumeric<T>(value, is_valid);
221 } 229 }
222 230
231 template <typename U>
232 constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
233 const U rhs) const {
234 using R = typename UnderlyingType<U>::type;
235 using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
236 // TODO(jschuh): This can be converted to the MathOp version and remain
237 // constexpr once we have C++14 support.
238 return CheckedNumeric<result_type>(
239 static_cast<result_type>(
240 IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
241 ? state_.value()
242 : Wrapper<U>::value(rhs)),
243 state_.is_valid() && Wrapper<U>::is_valid(rhs));
244 }
245
246 template <typename U>
247 constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
248 const U rhs) const {
249 using R = typename UnderlyingType<U>::type;
250 using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
251 // TODO(jschuh): This can be converted to the MathOp version and remain
252 // constexpr once we have C++14 support.
253 return CheckedNumeric<result_type>(
254 static_cast<result_type>(
255 IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
256 ? state_.value()
257 : Wrapper<U>::value(rhs)),
258 state_.is_valid() && Wrapper<U>::is_valid(rhs));
259 }
260
223 // This function is available only for integral types. It returns an unsigned 261 // This function is available only for integral types. It returns an unsigned
224 // integer of the same width as the source type, containing the absolute value 262 // integer of the same width as the source type, containing the absolute value
225 // of the source, and properly handling signed min. 263 // of the source, and properly handling signed min.
226 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> 264 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>
227 UnsignedAbs() const { 265 UnsignedAbs() const {
228 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 266 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
229 SafeUnsignedAbs(state_.value()), state_.is_valid()); 267 SafeUnsignedAbs(state_.value()), state_.is_valid());
230 } 268 }
231 269
232 CheckedNumeric& operator++() { 270 CheckedNumeric& operator++() {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 331
294 template <typename Src> 332 template <typename Src>
295 struct Wrapper<CheckedNumeric<Src>> { 333 struct Wrapper<CheckedNumeric<Src>> {
296 static constexpr bool is_valid(const CheckedNumeric<Src> v) { 334 static constexpr bool is_valid(const CheckedNumeric<Src> v) {
297 return v.IsValid(); 335 return v.IsValid();
298 } 336 }
299 static constexpr Src value(const CheckedNumeric<Src> v) { 337 static constexpr Src value(const CheckedNumeric<Src> v) {
300 return v.state_.value(); 338 return v.state_.value();
301 } 339 }
302 }; 340 };
341
342 template <typename Src>
343 struct Wrapper<StrictNumeric<Src>> {
344 static constexpr bool is_valid(const StrictNumeric<Src>) { return true; }
345 static constexpr Src value(const StrictNumeric<Src> v) {
346 return static_cast<Src>(v);
347 }
348 };
303 }; 349 };
304 350
305 // Convenience functions to avoid the ugly template disambiguator syntax. 351 // Convenience functions to avoid the ugly template disambiguator syntax.
306 template <typename Dst, typename Src> 352 template <typename Dst, typename Src>
307 constexpr bool IsValidForType(const CheckedNumeric<Src> value) { 353 constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
308 return value.template IsValid<Dst>(); 354 return value.template IsValid<Dst>();
309 } 355 }
310 356
311 template <typename Dst, typename Src> 357 template <typename Dst, typename Src>
312 constexpr StrictNumeric<Dst> ValueOrDieForType( 358 constexpr StrictNumeric<Dst> ValueOrDieForType(
(...skipping 30 matching lines...) Expand all
343 struct ResultType { 389 struct ResultType {
344 // The typedef was required here because MSVC fails to compile with "using". 390 // The typedef was required here because MSVC fails to compile with "using".
345 typedef 391 typedef
346 typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type 392 typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type
347 type; 393 type;
348 }; 394 };
349 395
350 // Convience wrapper to return a new CheckedNumeric from the provided arithmetic 396 // Convience wrapper to return a new CheckedNumeric from the provided arithmetic
351 // or CheckedNumericType. 397 // or CheckedNumericType.
352 template <typename T> 398 template <typename T>
353 CheckedNumeric<typename UnderlyingType<T>::type> CheckNum(T value) { 399 constexpr CheckedNumeric<typename UnderlyingType<T>::type> CheckNum(
400 const T value) {
354 return value; 401 return value;
355 } 402 }
356 403
357 // These implement the variadic wrapper for the math operations. 404 // These implement the variadic wrapper for the math operations.
358 template <template <typename, typename, typename> class M, 405 template <template <typename, typename, typename> class M,
359 typename L, 406 typename L,
360 typename R> 407 typename R>
361 CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs, 408 CheckedNumeric<typename MathWrapper<M, L, R>::type> ChkMathOp(const L lhs,
362 const R rhs) { 409 const R rhs) {
363 using Math = typename MathWrapper<M, L, R>::math; 410 using Math = typename MathWrapper<M, L, R>::math;
364 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 411 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
365 rhs); 412 rhs);
366 }; 413 }
367 414
415 // General purpose wrapper template for arithmetic operations.
368 template <template <typename, typename, typename> class M, 416 template <template <typename, typename, typename> class M,
369 typename L, 417 typename L,
370 typename R, 418 typename R,
371 typename... Args> 419 typename... Args>
372 CheckedNumeric<typename ResultType<M, L, R, Args...>::type> 420 CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
373 ChkMathOp(const L lhs, const R rhs, const Args... args) { 421 ChkMathOp(const L lhs, const R rhs, const Args... args) {
374 auto tmp = ChkMathOp<M>(lhs, rhs); 422 auto tmp = ChkMathOp<M>(lhs, rhs);
375 return tmp.IsValid() ? ChkMathOp<M>(tmp, args...) 423 return tmp.IsValid() ? ChkMathOp<M>(tmp, args...)
376 : decltype(ChkMathOp<M>(tmp, args...))(tmp); 424 : decltype(ChkMathOp<M>(tmp, args...))(tmp);
377 }; 425 };
378 426
379 // This is just boilerplate for the standard arithmetic operator overloads. 427 // The following macros are just boilerplate for the standard arithmetic
380 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 428 // operator overloads and variadic function templates. A macro isn't the nicest
429 // solution, but it beats rewriting these over and over again.
430 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME) \
431 template <typename L, typename R, typename... Args> \
432 CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \
433 Check##NAME(const L lhs, const R rhs, const Args... args) { \
434 return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...); \
435 }
436
381 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ 437 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
382 /* Binary arithmetic operator for all CheckedNumeric operations. */ \ 438 /* Binary arithmetic operator for all CheckedNumeric operations. */ \
383 template <typename L, typename R, \ 439 template <typename L, typename R, \
384 typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \ 440 typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \
385 nullptr> \ 441 nullptr> \
386 CheckedNumeric<typename MathWrapper<Checked##NAME##Op, L, R>::type> \ 442 CheckedNumeric<typename MathWrapper<Checked##NAME##Op, L, R>::type> \
387 operator OP(const L lhs, const R rhs) { \ 443 operator OP(const L lhs, const R rhs) { \
388 return decltype(lhs OP rhs)::template MathOp<Checked##NAME##Op>(lhs, rhs); \ 444 return decltype(lhs OP rhs)::template MathOp<Checked##NAME##Op>(lhs, rhs); \
389 } \ 445 } \
390 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ 446 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
391 template <typename L> \ 447 template <typename L> \
392 template <typename R> \ 448 template <typename R> \
393 CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(const R rhs) { \ 449 CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(const R rhs) { \
394 return MathOp<Checked##NAME##Op>(rhs); \ 450 return MathOp<Checked##NAME##Op>(rhs); \
395 } \ 451 } \
396 /* Variadic arithmetic functions that return CheckedNumeric. */ \ 452 /* Variadic arithmetic functions that return CheckedNumeric. */ \
397 template <typename L, typename R, typename... Args> \ 453 BASE_NUMERIC_ARITHMETIC_VARIADIC(NAME)
398 CheckedNumeric<typename ResultType<Checked##NAME##Op, L, R, Args...>::type> \
399 Check##NAME(const L lhs, const R rhs, const Args... args) { \
400 return ChkMathOp<Checked##NAME##Op, L, R, Args...>(lhs, rhs, args...); \
401 }
402 454
403 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) 455 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
404 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) 456 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
405 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) 457 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=)
406 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) 458 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
407 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) 459 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
408 BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=) 460 BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=)
409 BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=) 461 BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=)
410 BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=) 462 BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=)
411 BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=) 463 BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=)
412 BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=) 464 BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
465 BASE_NUMERIC_ARITHMETIC_VARIADIC(Max)
466 BASE_NUMERIC_ARITHMETIC_VARIADIC(Min)
413 467
468 #undef BASE_NUMERIC_ARITHMETIC_VARIADIC
414 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS 469 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
415 470
416 // These are some extra StrictNumeric operators to support simple pointer 471 // These are some extra StrictNumeric operators to support simple pointer
417 // arithmetic with our result types. Since wrapping on a pointer is always 472 // arithmetic with our result types. Since wrapping on a pointer is always
418 // bad, we trigger the CHECK condition here. 473 // bad, we trigger the CHECK condition here.
419 template <typename L, typename R> 474 template <typename L, typename R>
420 L* operator+(L* lhs, const StrictNumeric<R> rhs) { 475 L* operator+(L* lhs, const StrictNumeric<R> rhs) {
421 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 476 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
422 CheckMul(sizeof(L), static_cast<R>(rhs))) 477 CheckMul(sizeof(L), static_cast<R>(rhs)))
423 .template ValueOrDie<uintptr_t>(); 478 .template ValueOrDie<uintptr_t>();
424 return reinterpret_cast<L*>(result); 479 return reinterpret_cast<L*>(result);
425 } 480 }
426 481
427 template <typename L, typename R> 482 template <typename L, typename R>
428 L* operator-(L* lhs, const StrictNumeric<R> rhs) { 483 L* operator-(L* lhs, const StrictNumeric<R> rhs) {
429 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs), 484 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
430 CheckMul(sizeof(L), static_cast<R>(rhs))) 485 CheckMul(sizeof(L), static_cast<R>(rhs)))
431 .template ValueOrDie<uintptr_t>(); 486 .template ValueOrDie<uintptr_t>();
432 return reinterpret_cast<L*>(result); 487 return reinterpret_cast<L*>(result);
433 } 488 }
434 489
435 } // namespace internal 490 } // namespace internal
436 491
437 using internal::CheckedNumeric; 492 using internal::CheckedNumeric;
438 using internal::IsValidForType; 493 using internal::IsValidForType;
439 using internal::ValueOrDieForType; 494 using internal::ValueOrDieForType;
440 using internal::ValueOrDefaultForType; 495 using internal::ValueOrDefaultForType;
441 using internal::CheckNum; 496 using internal::CheckNum;
497 using internal::CheckMax;
498 using internal::CheckMin;
442 using internal::CheckAdd; 499 using internal::CheckAdd;
443 using internal::CheckSub; 500 using internal::CheckSub;
444 using internal::CheckMul; 501 using internal::CheckMul;
445 using internal::CheckDiv; 502 using internal::CheckDiv;
446 using internal::CheckMod; 503 using internal::CheckMod;
447 using internal::CheckLsh; 504 using internal::CheckLsh;
448 using internal::CheckRsh; 505 using internal::CheckRsh;
449 using internal::CheckAnd; 506 using internal::CheckAnd;
450 using internal::CheckOr; 507 using internal::CheckOr;
451 using internal::CheckXor; 508 using internal::CheckXor;
452 509
453 } // namespace base 510 } // namespace base
454 511
455 #endif // BASE_NUMERICS_SAFE_MATH_H_ 512 #endif // BASE_NUMERICS_SAFE_MATH_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_math_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698