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

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

Issue 2931323002: Split out code to be shared between CheckedNumeric and ClampedNumeric (Closed)
Patch Set: iwyu Created 3 years, 6 months 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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_IMPL_H_ 5 #ifndef BASE_NUMERICS_CHECKED_MATH_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ 6 #define BASE_NUMERICS_CHECKED_MATH_IMPL_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
11 #include <climits> 11 #include <climits>
12 #include <cmath> 12 #include <cmath>
13 #include <cstdlib> 13 #include <cstdlib>
14 #include <limits> 14 #include <limits>
15 #include <type_traits> 15 #include <type_traits>
16 16
17 #include "base/numerics/safe_conversions.h" 17 #include "base/numerics/safe_conversions.h"
18 #include "base/numerics/safe_math_shared_impl.h"
18 19
19 namespace base { 20 namespace base {
20 namespace internal { 21 namespace internal {
21 22
22 // Everything from here up to the floating point operations is portable C++,
23 // but it may not be fast. This code could be split based on
24 // platform/architecture and replaced with potentially faster implementations.
brucedawson 2017/06/12 21:09:22 This comment now gone from everywhere. Intentional
jschuh 2017/06/12 21:19:21 Yup. The move makes the code split clearer, and on
25
26 // This is used for UnsignedAbs, where we need to support floating-point
27 // template instantiations even though we don't actually support the operations.
28 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
29 // so the float versions will not compile.
30 template <typename Numeric,
31 bool IsInteger = std::is_integral<Numeric>::value,
32 bool IsFloat = std::is_floating_point<Numeric>::value>
33 struct UnsignedOrFloatForSize;
34
35 template <typename Numeric>
36 struct UnsignedOrFloatForSize<Numeric, true, false> {
37 using type = typename std::make_unsigned<Numeric>::type;
38 };
39
40 template <typename Numeric>
41 struct UnsignedOrFloatForSize<Numeric, false, true> {
42 using type = Numeric;
43 };
44
45 // Probe for builtin math overflow support on Clang and version check on GCC. 23 // Probe for builtin math overflow support on Clang and version check on GCC.
46 #if defined(__has_builtin) 24 #if defined(__has_builtin)
47 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) 25 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
48 #elif defined(__GNUC__) 26 #elif defined(__GNUC__)
49 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) 27 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5)
50 #else 28 #else
51 #define USE_OVERFLOW_BUILTINS (0) 29 #define USE_OVERFLOW_BUILTINS (0)
52 #endif 30 #endif
53 31
54 template <typename T> 32 template <typename T>
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 template <typename V = result_type> 415 template <typename V = result_type>
438 static bool Do(T x, U y, V* result) { 416 static bool Do(T x, U y, V* result) {
439 *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x) 417 *result = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
440 : static_cast<result_type>(y); 418 : static_cast<result_type>(y);
441 return true; 419 return true;
442 } 420 }
443 }; 421 };
444 422
445 // This is just boilerplate that wraps the standard floating point arithmetic. 423 // This is just boilerplate that wraps the standard floating point arithmetic.
446 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 424 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
447 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ 425 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
448 template <typename T, typename U> \ 426 template <typename T, typename U> \
449 struct Checked##NAME##Op< \ 427 struct Checked##NAME##Op< \
450 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ 428 T, U, \
451 std::is_floating_point<U>::value>::type> { \ 429 typename std::enable_if<std::is_floating_point<T>::value || \
452 using result_type = typename MaxExponentPromotion<T, U>::type; \ 430 std::is_floating_point<U>::value>::type> { \
453 template <typename V> \ 431 using result_type = typename MaxExponentPromotion<T, U>::type; \
454 static bool Do(T x, U y, V* result) { \ 432 template <typename V> \
455 using Promotion = typename MaxExponentPromotion<T, U>::type; \ 433 static bool Do(T x, U y, V* result) { \
456 Promotion presult = x OP y; \ 434 using Promotion = typename MaxExponentPromotion<T, U>::type; \
457 *result = static_cast<V>(presult); \ 435 Promotion presult = x OP y; \
458 return IsValueInRangeForNumericType<V>(presult); \ 436 *result = static_cast<V>(presult); \
459 } \ 437 return IsValueInRangeForNumericType<V>(presult); \
438 } \
460 }; 439 };
461 440
462 BASE_FLOAT_ARITHMETIC_OPS(Add, +) 441 BASE_FLOAT_ARITHMETIC_OPS(Add, +)
463 BASE_FLOAT_ARITHMETIC_OPS(Sub, -) 442 BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
464 BASE_FLOAT_ARITHMETIC_OPS(Mul, *) 443 BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
465 BASE_FLOAT_ARITHMETIC_OPS(Div, /) 444 BASE_FLOAT_ARITHMETIC_OPS(Div, /)
466 445
467 #undef BASE_FLOAT_ARITHMETIC_OPS 446 #undef BASE_FLOAT_ARITHMETIC_OPS
468 447
469 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
470 // floating points. These don't perform any overflow checking. Rather, they
471 // exhibit well-defined overflow semantics and rely on the caller to detect
472 // if an overflow occured.
473
474 template <typename T,
475 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
476 constexpr T NegateWrapper(T value) {
477 using UnsignedT = typename std::make_unsigned<T>::type;
478 // This will compile to a NEG on Intel, and is normal negation on ARM.
479 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
480 }
481
482 template <
483 typename T,
484 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
485 constexpr T NegateWrapper(T value) {
486 return -value;
487 }
488
489 template <typename T,
490 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
491 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
492 return ~value;
493 }
494
495 template <typename T,
496 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
497 constexpr T AbsWrapper(T value) {
498 return static_cast<T>(SafeUnsignedAbs(value));
499 }
500
501 template <
502 typename T,
503 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
504 constexpr T AbsWrapper(T value) {
505 return value < 0 ? -value : value;
506 }
507
508 // Floats carry around their validity state with them, but integers do not. So, 448 // Floats carry around their validity state with them, but integers do not. So,
509 // we wrap the underlying value in a specialization in order to hide that detail 449 // we wrap the underlying value in a specialization in order to hide that detail
510 // and expose an interface via accessors. 450 // and expose an interface via accessors.
511 enum NumericRepresentation { 451 enum NumericRepresentation {
512 NUMERIC_INTEGER, 452 NUMERIC_INTEGER,
513 NUMERIC_FLOATING, 453 NUMERIC_FLOATING,
514 NUMERIC_UNKNOWN 454 NUMERIC_UNKNOWN
515 }; 455 };
516 456
517 template <typename NumericType> 457 template <typename NumericType>
518 struct GetNumericRepresentation { 458 struct GetNumericRepresentation {
519 static const NumericRepresentation value = 459 static const NumericRepresentation value =
520 std::is_integral<NumericType>::value 460 std::is_integral<NumericType>::value
521 ? NUMERIC_INTEGER 461 ? NUMERIC_INTEGER
522 : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING 462 : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING
523 : NUMERIC_UNKNOWN); 463 : NUMERIC_UNKNOWN);
524 }; 464 };
525 465
526 template <typename T, NumericRepresentation type = 466 template <typename T,
527 GetNumericRepresentation<T>::value> 467 NumericRepresentation type = GetNumericRepresentation<T>::value>
528 class CheckedNumericState {}; 468 class CheckedNumericState {};
529 469
530 // Integrals require quite a bit of additional housekeeping to manage state. 470 // Integrals require quite a bit of additional housekeeping to manage state.
531 template <typename T> 471 template <typename T>
532 class CheckedNumericState<T, NUMERIC_INTEGER> { 472 class CheckedNumericState<T, NUMERIC_INTEGER> {
533 private: 473 private:
534 // is_valid_ precedes value_ because member intializers in the constructors 474 // is_valid_ precedes value_ because member intializers in the constructors
535 // are evaluated in field order, and is_valid_ must be read when initializing 475 // are evaluated in field order, and is_valid_ must be read when initializing
536 // value_. 476 // value_.
537 bool is_valid_; 477 bool is_valid_;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 558
619 constexpr bool is_valid() const { 559 constexpr bool is_valid() const {
620 // Written this way because std::isfinite is not reliably constexpr. 560 // Written this way because std::isfinite is not reliably constexpr.
621 // TODO(jschuh): Fix this if the libraries ever get fixed. 561 // TODO(jschuh): Fix this if the libraries ever get fixed.
622 return value_ <= std::numeric_limits<T>::max() && 562 return value_ <= std::numeric_limits<T>::max() &&
623 value_ >= std::numeric_limits<T>::lowest(); 563 value_ >= std::numeric_limits<T>::lowest();
624 } 564 }
625 constexpr T value() const { return value_; } 565 constexpr T value() const { return value_; }
626 }; 566 };
627 567
628 template <template <typename, typename, typename> class M,
629 typename L,
630 typename R>
631 struct MathWrapper {
632 using math = M<typename UnderlyingType<L>::type,
633 typename UnderlyingType<R>::type,
634 void>;
635 using type = typename math::result_type;
636 };
637
638 } // namespace internal 568 } // namespace internal
639 } // namespace base 569 } // namespace base
640 570
641 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 571 #endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698