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

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

Issue 2582063002: Revert of Support saturation overrides in saturated_cast (Closed)
Patch Set: 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.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_CONVERSIONS_IMPL_H_ 5 #ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
6 #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
7 7
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <limits> 10 #include <limits>
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >> 43 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >>
44 PositionOfSignBit<T>::value); 44 PositionOfSignBit<T>::value);
45 } 45 }
46 46
47 // This wrapper undoes the standard integer promotions. 47 // This wrapper undoes the standard integer promotions.
48 template <typename T> 48 template <typename T>
49 constexpr T BinaryComplement(T x) { 49 constexpr T BinaryComplement(T x) {
50 return static_cast<T>(~x); 50 return static_cast<T>(~x);
51 } 51 }
52 52
53 // Determines if a numeric value is negative without throwing compiler
54 // warnings on: unsigned(value) < 0.
55 template <typename T,
56 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
57 constexpr bool IsValueNegative(T value) {
58 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
59 return value < 0;
60 }
61
62 template <typename T,
63 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
64 constexpr bool IsValueNegative(T) {
65 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
66 return false;
67 }
68
69 // This performs a fast negation, returning a signed value. It works on unsigned
70 // arguments, but probably doesn't do what you want for any unsigned value
71 // larger than max / 2 + 1 (i.e. signed min cast to unsigned).
72 template <typename T>
73 constexpr typename std::make_signed<T>::type ConditionalNegate(
74 T x,
75 bool is_negative) {
76 static_assert(std::is_integral<T>::value, "Type must be integral");
77 using SignedT = typename std::make_signed<T>::type;
78 using UnsignedT = typename std::make_unsigned<T>::type;
79 return static_cast<SignedT>(
80 (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
81 }
82
83 // This performs a safe, non-branching absolute value via unsigned overflow. 53 // This performs a safe, non-branching absolute value via unsigned overflow.
84 template <typename T> 54 template <typename T>
85 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { 55 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) {
86 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); 56 static_assert(!std::is_signed<T>::value, "Types must be unsigned.");
87 return (value ^ sign_mask) - sign_mask; 57 return (value ^ sign_mask) - sign_mask;
88 } 58 }
89 59
90 template <typename T, 60 template <typename T,
91 typename std::enable_if<std::is_integral<T>::value && 61 typename std::enable_if<std::is_integral<T>::value &&
92 std::is_signed<T>::value>::type* = nullptr> 62 std::is_signed<T>::value>::type* = nullptr>
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 // value, a range check will erroneously pass. 174 // value, a range check will erroneously pass.
205 // Example: (4294967296f <= 4294967295u) // This is true due to a precision 175 // Example: (4294967296f <= 4294967295u) // This is true due to a precision
206 // // loss in rounding up to float. 176 // // loss in rounding up to float.
207 // 3. When the floating point value is then converted to an integral, the 177 // 3. When the floating point value is then converted to an integral, the
208 // resulting value is out of range for the target integral type and 178 // resulting value is out of range for the target integral type and
209 // thus is implementation defined. 179 // thus is implementation defined.
210 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. 180 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
211 // To fix this bug we manually truncate the maximum value when the destination 181 // To fix this bug we manually truncate the maximum value when the destination
212 // type is an integral of larger precision than the source floating-point type, 182 // type is an integral of larger precision than the source floating-point type,
213 // such that the resulting maximum is represented exactly as a floating point. 183 // such that the resulting maximum is represented exactly as a floating point.
214 template <typename Dst, 184 template <typename Dst, typename Src>
215 typename Src,
216 template <typename> class Bounds = std::numeric_limits>
217 struct NarrowingRange { 185 struct NarrowingRange {
218 using SrcLimits = typename std::numeric_limits<Src>; 186 using SrcLimits = typename std::numeric_limits<Src>;
219 using DstLimits = typename std::numeric_limits<Dst>; 187 using DstLimits = typename std::numeric_limits<Dst>;
188 // The following logic avoids warnings where the max function is
189 // instantiated with invalid values for a bit shift (even though
190 // such a function can never be called).
191 static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
192 SrcLimits::digits < DstLimits::digits &&
193 SrcLimits::is_iec559 &&
194 DstLimits::is_integer)
195 ? (DstLimits::digits - SrcLimits::digits)
196 : 0;
220 197
221 // Computes the mask required to make an accurate comparison between types. 198 static constexpr Dst max() {
222 static const int kShift = 199 // We use UINTMAX_C below to avoid compiler warnings about shifting floating
223 (MaxExponent<Src>::value > MaxExponent<Dst>::value && 200 // points. Since it's a compile time calculation, it shouldn't have any
224 SrcLimits::digits < DstLimits::digits) 201 // performance impact.
225 ? (DstLimits::digits - SrcLimits::digits) 202 return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
226 : 0;
227 template <
228 typename T,
229 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
230
231 // Masks out the integer bits that are beyond the precision of the
232 // intermediate type used for comparison.
233 static constexpr T Adjust(T value) {
234 static_assert(std::is_same<T, Dst>::value, "");
235 static_assert(kShift < DstLimits::digits, "");
236 return static_cast<T>(
237 ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)),
238 IsValueNegative(value)));
239 } 203 }
240 204
241 template <typename T, 205 static constexpr Dst lowest() { return DstLimits::lowest(); }
242 typename std::enable_if<std::is_floating_point<T>::value>::type* =
243 nullptr>
244 static constexpr T Adjust(T value) {
245 static_assert(std::is_same<T, Dst>::value, "");
246 static_assert(kShift == 0, "");
247 return value;
248 }
249
250 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
251 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
252 }; 206 };
253 207
254 template <typename Dst, 208 template <typename Dst,
255 typename Src, 209 typename Src,
256 IntegerRepresentation DstSign = std::is_signed<Dst>::value 210 IntegerRepresentation DstSign = std::is_signed<Dst>::value
257 ? INTEGER_REPRESENTATION_SIGNED 211 ? INTEGER_REPRESENTATION_SIGNED
258 : INTEGER_REPRESENTATION_UNSIGNED, 212 : INTEGER_REPRESENTATION_UNSIGNED,
259 IntegerRepresentation SrcSign = std::is_signed<Src>::value 213 IntegerRepresentation SrcSign = std::is_signed<Src>::value
260 ? INTEGER_REPRESENTATION_SIGNED 214 ? INTEGER_REPRESENTATION_SIGNED
261 : INTEGER_REPRESENTATION_UNSIGNED, 215 : INTEGER_REPRESENTATION_UNSIGNED,
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 static_cast<BigType>(static_cast<L>(lhs)), 648 static_cast<BigType>(static_cast<L>(lhs)),
695 static_cast<BigType>(static_cast<R>(rhs))) 649 static_cast<BigType>(static_cast<R>(rhs)))
696 // Let the template functions figure it out for mixed types. 650 // Let the template functions figure it out for mixed types.
697 : C<L, R>::Test(lhs, rhs); 651 : C<L, R>::Test(lhs, rhs);
698 }; 652 };
699 653
700 } // namespace internal 654 } // namespace internal
701 } // namespace base 655 } // namespace base
702 656
703 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 657 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698