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

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

Issue 2566733002: Performance optimizations for base/numerics absolute value and multiply (Closed)
Patch Set: one more nit 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_numerics_unittest.cc » ('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_IMPL_H_ 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 24 matching lines...) Expand all
35 template <typename Numeric> 35 template <typename Numeric>
36 struct UnsignedOrFloatForSize<Numeric, true, false> { 36 struct UnsignedOrFloatForSize<Numeric, true, false> {
37 using type = typename std::make_unsigned<Numeric>::type; 37 using type = typename std::make_unsigned<Numeric>::type;
38 }; 38 };
39 39
40 template <typename Numeric> 40 template <typename Numeric>
41 struct UnsignedOrFloatForSize<Numeric, false, true> { 41 struct UnsignedOrFloatForSize<Numeric, false, true> {
42 using type = Numeric; 42 using type = Numeric;
43 }; 43 };
44 44
45 // Helper templates for integer manipulations.
46
47 template <typename T>
48 constexpr bool HasSignBit(T x) {
49 // Cast to unsigned since right shift on signed is undefined.
50 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >>
51 PositionOfSignBit<T>::value);
52 }
53
54 // This wrapper undoes the standard integer promotions.
55 template <typename T>
56 constexpr T BinaryComplement(T x) {
57 return static_cast<T>(~x);
58 }
59
60 // Probe for builtin math overflow support on Clang and version check on GCC. 45 // Probe for builtin math overflow support on Clang and version check on GCC.
61 #if defined(__has_builtin) 46 #if defined(__has_builtin)
62 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) 47 #define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
63 #elif defined(__GNUC__) 48 #elif defined(__GNUC__)
64 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) 49 #define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5)
65 #else 50 #else
66 #define USE_OVERFLOW_BUILTINS (0) 51 #define USE_OVERFLOW_BUILTINS (0)
67 #endif 52 #endif
68 53
69 template <typename T, 54 template <typename T,
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 *result = static_cast<T>(tmp); 170 *result = static_cast<T>(tmp);
186 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; 171 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID;
187 } 172 }
188 173
189 template <typename T, 174 template <typename T,
190 typename std::enable_if< 175 typename std::enable_if<
191 std::is_integral<T>::value && std::is_signed<T>::value && 176 std::is_integral<T>::value && std::is_signed<T>::value &&
192 ((IntegerBitsPlusSign<T>::value * 2) > 177 ((IntegerBitsPlusSign<T>::value * 2) >
193 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> 178 IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr>
194 bool CheckedMulImpl(T x, T y, T* result) { 179 bool CheckedMulImpl(T x, T y, T* result) {
195 if (x && y) { 180 // Since the value of x*y is potentially undefined if we have a signed type,
196 if (x > 0) { 181 // we compute it using the unsigned type of the same size.
197 if (y > 0) { 182 using UnsignedDst = typename std::make_unsigned<T>::type;
198 if (x > std::numeric_limits<T>::max() / y) 183 const T is_negative = HasSignBit(x) ^ HasSignBit(y);
199 return false; 184 const UnsignedDst ux = SafeUnsignedAbs(x);
200 } else { 185 const UnsignedDst uy = SafeUnsignedAbs(y);
201 if (y < std::numeric_limits<T>::lowest() / x) 186 UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
202 return false; 187 // This is a non-branching conditional negation.
203 } 188 *result = static_cast<T>((uresult ^ -is_negative) + is_negative);
scottmg 2016/12/10 01:01:31 I would have moved that before this line instead,
204 } else { 189 // This uses the unsigned overflow check on the absolute value, with a +1
205 if (y > 0) { 190 // bound for a negative result.
206 if (x < std::numeric_limits<T>::lowest() / y) 191 return (uy == 0 ||
207 return false; 192 ux <= (static_cast<UnsignedDst>(std::numeric_limits<T>::max()) +
208 } else { 193 is_negative) /
209 if (y < std::numeric_limits<T>::max() / x) 194 uy);
210 return false;
211 }
212 }
213 }
214 *result = x * y;
215 return true;
216 } 195 }
217 196
218 template <typename T, 197 template <typename T,
219 typename std::enable_if< 198 typename std::enable_if<
220 std::is_integral<T>::value && !std::is_signed<T>::value && 199 std::is_integral<T>::value && !std::is_signed<T>::value &&
221 ((IntegerBitsPlusSign<T>::value * 2) > 200 ((IntegerBitsPlusSign<T>::value * 2) >
222 IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr> 201 IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr>
223 bool CheckedMulImpl(T x, T y, T* result) { 202 bool CheckedMulImpl(T x, T y, T* result) {
224 *result = x * y; 203 *result = x * y;
225 return (y == 0 || x <= std::numeric_limits<T>::max() / y); 204 return (y == 0 || x <= std::numeric_limits<T>::max() / y);
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 !std::is_signed<T>::value>::type* = nullptr> 501 !std::is_signed<T>::value>::type* = nullptr>
523 bool CheckedInv(T value, T* result) { 502 bool CheckedInv(T value, T* result) {
524 *result = ~value; 503 *result = ~value;
525 return true; 504 return true;
526 } 505 }
527 506
528 template <typename T, 507 template <typename T,
529 typename std::enable_if<std::is_integral<T>::value && 508 typename std::enable_if<std::is_integral<T>::value &&
530 std::is_signed<T>::value>::type* = nullptr> 509 std::is_signed<T>::value>::type* = nullptr>
531 bool CheckedAbs(T value, T* result) { 510 bool CheckedAbs(T value, T* result) {
532 if (value != std::numeric_limits<T>::lowest()) { 511 *result = static_cast<T>(SafeUnsignedAbs(value));
533 *result = std::abs(value); 512 return *result != std::numeric_limits<T>::lowest();
534 return true;
535 }
536 return false;
537 } 513 }
538 514
539 template <typename T, 515 template <typename T,
540 typename std::enable_if<std::is_integral<T>::value && 516 typename std::enable_if<std::is_integral<T>::value &&
541 !std::is_signed<T>::value>::type* = nullptr> 517 !std::is_signed<T>::value>::type* = nullptr>
542 bool CheckedAbs(T value, T* result) { 518 bool CheckedAbs(T value, T* result) {
543 // T is unsigned, so |value| must already be positive. 519 // T is unsigned, so |value| must already be positive.
544 *result = value; 520 *result = value;
545 return true; 521 return true;
546 } 522 }
547 523
548 template <typename T,
549 typename std::enable_if<std::is_integral<T>::value &&
550 std::is_signed<T>::value>::type* = nullptr>
551 constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
552 using UnsignedT = typename std::make_unsigned<T>::type;
553 return value == std::numeric_limits<T>::lowest()
554 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
555 : static_cast<UnsignedT>(std::abs(value));
556 }
557
558 template <typename T,
559 typename std::enable_if<std::is_integral<T>::value &&
560 !std::is_signed<T>::value>::type* = nullptr>
561 constexpr T SafeUnsignedAbs(T value) {
562 // T is unsigned, so |value| must already be positive.
563 return static_cast<T>(value);
564 }
565
566 // This is just boilerplate that wraps the standard floating point arithmetic. 524 // This is just boilerplate that wraps the standard floating point arithmetic.
567 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 525 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
568 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ 526 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
569 template <typename T, typename U> \ 527 template <typename T, typename U> \
570 struct Checked##NAME##Op< \ 528 struct Checked##NAME##Op< \
571 T, U, typename std::enable_if<std::is_floating_point<T>::value || \ 529 T, U, typename std::enable_if<std::is_floating_point<T>::value || \
572 std::is_floating_point<U>::value>::type> { \ 530 std::is_floating_point<U>::value>::type> { \
573 using result_type = typename MaxExponentPromotion<T, U>::type; \ 531 using result_type = typename MaxExponentPromotion<T, U>::type; \
574 template <typename V> \ 532 template <typename V> \
575 static bool Do(T x, U y, V* result) { \ 533 static bool Do(T x, U y, V* result) { \
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 using math = M<typename UnderlyingType<L>::type, 688 using math = M<typename UnderlyingType<L>::type,
731 typename UnderlyingType<R>::type, 689 typename UnderlyingType<R>::type,
732 void>; 690 void>;
733 using type = typename math::result_type; 691 using type = typename math::result_type;
734 }; 692 };
735 693
736 } // namespace internal 694 } // namespace internal
737 } // namespace base 695 } // namespace base
738 696
739 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 697 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698