OLD | NEW |
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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 | 159 |
160 // Signed to unsigned: Dst cannot be statically determined to contain Src. | 160 // Signed to unsigned: Dst cannot be statically determined to contain Src. |
161 template <typename Dst, typename Src> | 161 template <typename Dst, typename Src> |
162 struct StaticDstRangeRelationToSrcRange<Dst, | 162 struct StaticDstRangeRelationToSrcRange<Dst, |
163 Src, | 163 Src, |
164 INTEGER_REPRESENTATION_UNSIGNED, | 164 INTEGER_REPRESENTATION_UNSIGNED, |
165 INTEGER_REPRESENTATION_SIGNED> { | 165 INTEGER_REPRESENTATION_SIGNED> { |
166 static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; | 166 static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; |
167 }; | 167 }; |
168 | 168 |
169 enum RangeConstraintEnum { | 169 enum RangeConstraint { |
170 RANGE_VALID = 0x0, // Value can be represented by the destination type. | 170 RANGE_VALID = 0x0, // Value can be represented by the destination type. |
171 RANGE_OVERFLOW = 0x1, // Value would overflow. | 171 RANGE_UNDERFLOW = 0x1, // Value would overflow. |
172 RANGE_UNDERFLOW = 0x2, // Value would underflow. | 172 RANGE_OVERFLOW = 0x2, // Value would underflow. |
173 RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). | 173 RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). |
174 }; | 174 }; |
175 | 175 |
176 // This class wraps the range constraints as separate booleans so the compiler | 176 // Helper function for coercing an int back to a RangeContraint. |
177 // can identify constants and eliminate unused code paths. | 177 constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) { |
178 class RangeConstraint { | 178 // TODO(jschuh): Once we get full C++14 support we want this |
179 public: | 179 // assert(integer_range_constraint >= RANGE_VALID && |
180 constexpr RangeConstraint(bool is_in_upper_bound, bool is_in_lower_bound) | 180 // integer_range_constraint <= RANGE_INVALID) |
181 : is_overflow_(!is_in_upper_bound), is_underflow_(!is_in_lower_bound) {} | 181 return static_cast<RangeConstraint>(integer_range_constraint); |
182 constexpr RangeConstraint() : is_overflow_(0), is_underflow_(0) {} | 182 } |
183 constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; } | |
184 constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; } | |
185 constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; } | |
186 constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; } | |
187 | 183 |
188 // These are some wrappers to make the tests a bit cleaner. | 184 // This function creates a RangeConstraint from an upper and lower bound |
189 constexpr operator RangeConstraintEnum() const { | 185 // check by taking advantage of the fact that only NaN can be out of range in |
190 return static_cast<RangeConstraintEnum>( | 186 // both directions at once. |
191 static_cast<int>(is_overflow_) | static_cast<int>(is_underflow_) << 1); | 187 constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, |
192 } | 188 bool is_in_lower_bound) { |
193 constexpr bool operator==(const RangeConstraintEnum rhs) const { | 189 return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | |
194 return rhs == static_cast<RangeConstraintEnum>(*this); | 190 (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); |
195 } | 191 } |
196 | |
197 private: | |
198 const bool is_overflow_; | |
199 const bool is_underflow_; | |
200 }; | |
201 | 192 |
202 // The following helper template addresses a corner case in range checks for | 193 // The following helper template addresses a corner case in range checks for |
203 // conversion from a floating-point type to an integral type of smaller range | 194 // conversion from a floating-point type to an integral type of smaller range |
204 // but larger precision (e.g. float -> unsigned). The problem is as follows: | 195 // but larger precision (e.g. float -> unsigned). The problem is as follows: |
205 // 1. Integral maximum is always one less than a power of two, so it must be | 196 // 1. Integral maximum is always one less than a power of two, so it must be |
206 // truncated to fit the mantissa of the floating point. The direction of | 197 // truncated to fit the mantissa of the floating point. The direction of |
207 // rounding is implementation defined, but by default it's always IEEE | 198 // rounding is implementation defined, but by default it's always IEEE |
208 // floats, which round to nearest and thus result in a value of larger | 199 // floats, which round to nearest and thus result in a value of larger |
209 // magnitude than the integral value. | 200 // magnitude than the integral value. |
210 // Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX | 201 // Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX |
211 // // is 4294967295u. | 202 // // is 4294967295u. |
212 // 2. If the floating point value is equal to the promoted integral maximum | 203 // 2. If the floating point value is equal to the promoted integral maximum |
213 // value, a range check will erroneously pass. | 204 // value, a range check will erroneously pass. |
214 // Example: (4294967296f <= 4294967295u) // This is true due to a precision | 205 // Example: (4294967296f <= 4294967295u) // This is true due to a precision |
215 // // loss in rounding up to float. | 206 // // loss in rounding up to float. |
216 // 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 |
217 // 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 |
218 // thus is implementation defined. | 209 // thus is implementation defined. |
219 // 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. |
220 // 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 |
221 // 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, |
222 // 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. |
223 template <typename Dst, typename Src, template <typename> class Bounds> | 214 template <typename Dst, |
| 215 typename Src, |
| 216 template <typename> class Bounds = std::numeric_limits> |
224 struct NarrowingRange { | 217 struct NarrowingRange { |
225 using SrcLimits = std::numeric_limits<Src>; | 218 using SrcLimits = typename std::numeric_limits<Src>; |
226 using DstLimits = typename std::numeric_limits<Dst>; | 219 using DstLimits = typename std::numeric_limits<Dst>; |
227 | 220 |
228 // Computes the mask required to make an accurate comparison between types. | 221 // Computes the mask required to make an accurate comparison between types. |
229 static const int kShift = | 222 static const int kShift = |
230 (MaxExponent<Src>::value > MaxExponent<Dst>::value && | 223 (MaxExponent<Src>::value > MaxExponent<Dst>::value && |
231 SrcLimits::digits < DstLimits::digits) | 224 SrcLimits::digits < DstLimits::digits) |
232 ? (DstLimits::digits - SrcLimits::digits) | 225 ? (DstLimits::digits - SrcLimits::digits) |
233 : 0; | 226 : 0; |
234 template < | 227 template < |
235 typename T, | 228 typename T, |
(...skipping 17 matching lines...) Expand all Loading... |
253 static_assert(kShift == 0, ""); | 246 static_assert(kShift == 0, ""); |
254 return value; | 247 return value; |
255 } | 248 } |
256 | 249 |
257 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } | 250 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); } |
258 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } | 251 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); } |
259 }; | 252 }; |
260 | 253 |
261 template <typename Dst, | 254 template <typename Dst, |
262 typename Src, | 255 typename Src, |
263 template <typename> class Bounds, | |
264 IntegerRepresentation DstSign = std::is_signed<Dst>::value | 256 IntegerRepresentation DstSign = std::is_signed<Dst>::value |
265 ? INTEGER_REPRESENTATION_SIGNED | 257 ? INTEGER_REPRESENTATION_SIGNED |
266 : INTEGER_REPRESENTATION_UNSIGNED, | 258 : INTEGER_REPRESENTATION_UNSIGNED, |
267 IntegerRepresentation SrcSign = std::is_signed<Src>::value | 259 IntegerRepresentation SrcSign = std::is_signed<Src>::value |
268 ? INTEGER_REPRESENTATION_SIGNED | 260 ? INTEGER_REPRESENTATION_SIGNED |
269 : INTEGER_REPRESENTATION_UNSIGNED, | 261 : INTEGER_REPRESENTATION_UNSIGNED, |
270 NumericRangeRepresentation DstRange = | 262 NumericRangeRepresentation DstRange = |
271 StaticDstRangeRelationToSrcRange<Dst, Src>::value> | 263 StaticDstRangeRelationToSrcRange<Dst, Src>::value> |
272 struct DstRangeRelationToSrcRangeImpl; | 264 struct DstRangeRelationToSrcRangeImpl; |
273 | 265 |
274 // The following templates are for ranges that must be verified at runtime. We | 266 // The following templates are for ranges that must be verified at runtime. We |
275 // split it into checks based on signedness to avoid confusing casts and | 267 // split it into checks based on signedness to avoid confusing casts and |
276 // compiler warnings on signed an unsigned comparisons. | 268 // compiler warnings on signed an unsigned comparisons. |
277 | 269 |
278 // Same sign narrowing: The range is contained for normal limits. | 270 // Dst range is statically determined to contain Src: Nothing to check. |
279 template <typename Dst, | 271 template <typename Dst, |
280 typename Src, | 272 typename Src, |
281 template <typename> class Bounds, | |
282 IntegerRepresentation DstSign, | 273 IntegerRepresentation DstSign, |
283 IntegerRepresentation SrcSign> | 274 IntegerRepresentation SrcSign> |
284 struct DstRangeRelationToSrcRangeImpl<Dst, | 275 struct DstRangeRelationToSrcRangeImpl<Dst, |
285 Src, | 276 Src, |
286 Bounds, | |
287 DstSign, | 277 DstSign, |
288 SrcSign, | 278 SrcSign, |
289 NUMERIC_RANGE_CONTAINED> { | 279 NUMERIC_RANGE_CONTAINED> { |
290 static constexpr RangeConstraint Check(Src value) { | 280 static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; } |
291 using SrcLimits = std::numeric_limits<Src>; | |
292 using DstLimits = NarrowingRange<Dst, Src, Bounds>; | |
293 return RangeConstraint( | |
294 static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() || | |
295 static_cast<Dst>(value) <= DstLimits::max(), | |
296 static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() || | |
297 static_cast<Dst>(value) >= DstLimits::lowest()); | |
298 } | |
299 }; | 281 }; |
300 | 282 |
301 // Signed to signed narrowing: Both the upper and lower boundaries may be | 283 // Signed to signed narrowing: Both the upper and lower boundaries may be |
302 // exceeded for standard limits. | 284 // exceeded. |
303 template <typename Dst, typename Src, template <typename> class Bounds> | 285 template <typename Dst, typename Src> |
304 struct DstRangeRelationToSrcRangeImpl<Dst, | 286 struct DstRangeRelationToSrcRangeImpl<Dst, |
305 Src, | 287 Src, |
306 Bounds, | |
307 INTEGER_REPRESENTATION_SIGNED, | 288 INTEGER_REPRESENTATION_SIGNED, |
308 INTEGER_REPRESENTATION_SIGNED, | 289 INTEGER_REPRESENTATION_SIGNED, |
309 NUMERIC_RANGE_NOT_CONTAINED> { | 290 NUMERIC_RANGE_NOT_CONTAINED> { |
310 static constexpr RangeConstraint Check(Src value) { | 291 static constexpr RangeConstraint Check(Src value) { |
311 using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 292 return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()), |
312 return RangeConstraint(value <= DstLimits::max(), | 293 (value >= NarrowingRange<Dst, Src>::lowest())); |
313 value >= DstLimits::lowest()); | |
314 } | 294 } |
315 }; | 295 }; |
316 | 296 |
317 // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for | 297 // Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. |
318 // standard limits. | 298 template <typename Dst, typename Src> |
319 template <typename Dst, typename Src, template <typename> class Bounds> | |
320 struct DstRangeRelationToSrcRangeImpl<Dst, | 299 struct DstRangeRelationToSrcRangeImpl<Dst, |
321 Src, | 300 Src, |
322 Bounds, | |
323 INTEGER_REPRESENTATION_UNSIGNED, | 301 INTEGER_REPRESENTATION_UNSIGNED, |
324 INTEGER_REPRESENTATION_UNSIGNED, | 302 INTEGER_REPRESENTATION_UNSIGNED, |
325 NUMERIC_RANGE_NOT_CONTAINED> { | 303 NUMERIC_RANGE_NOT_CONTAINED> { |
326 static constexpr RangeConstraint Check(Src value) { | 304 static constexpr RangeConstraint Check(Src value) { |
327 using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 305 return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true); |
328 return RangeConstraint( | |
329 value <= DstLimits::max(), | |
330 DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest()); | |
331 } | 306 } |
332 }; | 307 }; |
333 | 308 |
334 // Unsigned to signed: Only the upper bound can be exceeded for standard limits. | 309 // Unsigned to signed: The upper boundary may be exceeded. |
335 template <typename Dst, typename Src, template <typename> class Bounds> | 310 template <typename Dst, typename Src> |
336 struct DstRangeRelationToSrcRangeImpl<Dst, | 311 struct DstRangeRelationToSrcRangeImpl<Dst, |
337 Src, | 312 Src, |
338 Bounds, | |
339 INTEGER_REPRESENTATION_SIGNED, | 313 INTEGER_REPRESENTATION_SIGNED, |
340 INTEGER_REPRESENTATION_UNSIGNED, | 314 INTEGER_REPRESENTATION_UNSIGNED, |
341 NUMERIC_RANGE_NOT_CONTAINED> { | 315 NUMERIC_RANGE_NOT_CONTAINED> { |
342 static constexpr RangeConstraint Check(Src value) { | 316 static constexpr RangeConstraint Check(Src value) { |
343 using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 317 return IntegerBitsPlusSign<Dst>::value > IntegerBitsPlusSign<Src>::value |
344 using Promotion = decltype(Src() + Dst()); | 318 ? RANGE_VALID |
345 return RangeConstraint(static_cast<Promotion>(value) <= | 319 : GetRangeConstraint( |
346 static_cast<Promotion>(DstLimits::max()), | 320 value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()), |
347 DstLimits::lowest() <= Dst(0) || | 321 true); |
348 static_cast<Promotion>(value) >= | |
349 static_cast<Promotion>(DstLimits::lowest())); | |
350 } | 322 } |
351 }; | 323 }; |
352 | 324 |
353 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, | 325 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, |
354 // and any negative value exceeds the lower boundary for standard limits. | 326 // and any negative value exceeds the lower boundary. |
355 template <typename Dst, typename Src, template <typename> class Bounds> | 327 template <typename Dst, typename Src> |
356 struct DstRangeRelationToSrcRangeImpl<Dst, | 328 struct DstRangeRelationToSrcRangeImpl<Dst, |
357 Src, | 329 Src, |
358 Bounds, | |
359 INTEGER_REPRESENTATION_UNSIGNED, | 330 INTEGER_REPRESENTATION_UNSIGNED, |
360 INTEGER_REPRESENTATION_SIGNED, | 331 INTEGER_REPRESENTATION_SIGNED, |
361 NUMERIC_RANGE_NOT_CONTAINED> { | 332 NUMERIC_RANGE_NOT_CONTAINED> { |
362 static constexpr RangeConstraint Check(Src value) { | 333 static constexpr RangeConstraint Check(Src value) { |
363 using SrcLimits = std::numeric_limits<Src>; | 334 return (MaxExponent<Dst>::value >= MaxExponent<Src>::value) |
364 using DstLimits = NarrowingRange<Dst, Src, Bounds>; | 335 ? GetRangeConstraint(true, value >= static_cast<Src>(0)) |
365 using Promotion = decltype(Src() + Dst()); | 336 : GetRangeConstraint( |
366 return RangeConstraint( | 337 value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()), |
367 static_cast<Promotion>(SrcLimits::max()) <= | 338 value >= static_cast<Src>(0)); |
368 static_cast<Promotion>(DstLimits::max()) || | |
369 static_cast<Promotion>(value) <= | |
370 static_cast<Promotion>(DstLimits::max()), | |
371 value >= Src(0) && (DstLimits::lowest() == 0 || | |
372 static_cast<Dst>(value) >= DstLimits::lowest())); | |
373 } | 339 } |
374 }; | 340 }; |
375 | 341 |
376 template <typename Dst, | 342 template <typename Dst, typename Src> |
377 template <typename> class Bounds = std::numeric_limits, | |
378 typename Src> | |
379 constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) { | 343 constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) { |
380 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); | 344 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); |
381 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); | 345 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); |
382 static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), ""); | 346 return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value); |
383 return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value); | |
384 } | 347 } |
385 | 348 |
386 // Integer promotion templates used by the portable checked integer arithmetic. | 349 // Integer promotion templates used by the portable checked integer arithmetic. |
387 template <size_t Size, bool IsSigned> | 350 template <size_t Size, bool IsSigned> |
388 struct IntegerForDigitsAndSign; | 351 struct IntegerForDigitsAndSign; |
389 | 352 |
390 #define INTEGER_FOR_DIGITS_AND_SIGN(I) \ | 353 #define INTEGER_FOR_DIGITS_AND_SIGN(I) \ |
391 template <> \ | 354 template <> \ |
392 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \ | 355 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \ |
393 std::is_signed<I>::value> { \ | 356 std::is_signed<I>::value> { \ |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 static_cast<BigType>(static_cast<L>(lhs)), | 694 static_cast<BigType>(static_cast<L>(lhs)), |
732 static_cast<BigType>(static_cast<R>(rhs))) | 695 static_cast<BigType>(static_cast<R>(rhs))) |
733 // Let the template functions figure it out for mixed types. | 696 // Let the template functions figure it out for mixed types. |
734 : C<L, R>::Test(lhs, rhs); | 697 : C<L, R>::Test(lhs, rhs); |
735 }; | 698 }; |
736 | 699 |
737 } // namespace internal | 700 } // namespace internal |
738 } // namespace base | 701 } // namespace base |
739 | 702 |
740 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ | 703 #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ |
OLD | NEW |