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

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

Issue 2578613002: Support saturation overrides in saturated_cast (Closed)
Patch Set: compile fix 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
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
53 // This performs a safe, non-branching absolute value via unsigned overflow. 83 // This performs a safe, non-branching absolute value via unsigned overflow.
54 template <typename T> 84 template <typename T>
55 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) { 85 constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) {
56 static_assert(!std::is_signed<T>::value, "Types must be unsigned."); 86 static_assert(!std::is_signed<T>::value, "Types must be unsigned.");
57 return (value ^ sign_mask) - sign_mask; 87 return (value ^ sign_mask) - sign_mask;
58 } 88 }
59 89
60 template <typename T, 90 template <typename T,
61 typename std::enable_if<std::is_integral<T>::value && 91 typename std::enable_if<std::is_integral<T>::value &&
62 std::is_signed<T>::value>::type* = nullptr> 92 std::is_signed<T>::value>::type* = nullptr>
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 // value, a range check will erroneously pass. 204 // value, a range check will erroneously pass.
175 // Example: (4294967296f <= 4294967295u) // This is true due to a precision 205 // Example: (4294967296f <= 4294967295u) // This is true due to a precision
176 // // loss in rounding up to float. 206 // // loss in rounding up to float.
177 // 3. When the floating point value is then converted to an integral, the 207 // 3. When the floating point value is then converted to an integral, the
178 // resulting value is out of range for the target integral type and 208 // resulting value is out of range for the target integral type and
179 // thus is implementation defined. 209 // thus is implementation defined.
180 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. 210 // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
181 // To fix this bug we manually truncate the maximum value when the destination 211 // To fix this bug we manually truncate the maximum value when the destination
182 // type is an integral of larger precision than the source floating-point type, 212 // type is an integral of larger precision than the source floating-point type,
183 // such that the resulting maximum is represented exactly as a floating point. 213 // such that the resulting maximum is represented exactly as a floating point.
184 template <typename Dst, typename Src> 214 template <typename Dst,
215 typename Src,
216 template <typename> class Bounds = std::numeric_limits>
185 struct NarrowingRange { 217 struct NarrowingRange {
186 using SrcLimits = typename std::numeric_limits<Src>; 218 using SrcLimits = typename std::numeric_limits<Src>;
187 using DstLimits = typename std::numeric_limits<Dst>; 219 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;
197 220
198 static constexpr Dst max() { 221 // Computes the mask required to make an accurate comparison between types.
199 // We use UINTMAX_C below to avoid compiler warnings about shifting floating 222 static const int kShift =
200 // points. Since it's a compile time calculation, it shouldn't have any 223 (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
201 // performance impact. 224 SrcLimits::digits < DstLimits::digits)
202 return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); 225 ? (DstLimits::digits - SrcLimits::digits)
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)),
eae 2016/12/15 23:07:46 Nice!
238 IsValueNegative(value)));
203 } 239 }
204 240
205 static constexpr Dst lowest() { return DstLimits::lowest(); } 241 template <typename T,
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()); }
206 }; 252 };
207 253
208 template <typename Dst, 254 template <typename Dst,
209 typename Src, 255 typename Src,
210 IntegerRepresentation DstSign = std::is_signed<Dst>::value 256 IntegerRepresentation DstSign = std::is_signed<Dst>::value
211 ? INTEGER_REPRESENTATION_SIGNED 257 ? INTEGER_REPRESENTATION_SIGNED
212 : INTEGER_REPRESENTATION_UNSIGNED, 258 : INTEGER_REPRESENTATION_UNSIGNED,
213 IntegerRepresentation SrcSign = std::is_signed<Src>::value 259 IntegerRepresentation SrcSign = std::is_signed<Src>::value
214 ? INTEGER_REPRESENTATION_SIGNED 260 ? INTEGER_REPRESENTATION_SIGNED
215 : INTEGER_REPRESENTATION_UNSIGNED, 261 : INTEGER_REPRESENTATION_UNSIGNED,
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 static_cast<BigType>(static_cast<L>(lhs)), 694 static_cast<BigType>(static_cast<L>(lhs)),
649 static_cast<BigType>(static_cast<R>(rhs))) 695 static_cast<BigType>(static_cast<R>(rhs)))
650 // Let the template functions figure it out for mixed types. 696 // Let the template functions figure it out for mixed types.
651 : C<L, R>::Test(lhs, rhs); 697 : C<L, R>::Test(lhs, rhs);
652 }; 698 };
653 699
654 } // namespace internal 700 } // namespace internal
655 } // namespace base 701 } // namespace base
656 702
657 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ 703 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698