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

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

Issue 2473513002: Take more current safe_math_impl.h from upstream. (Closed)
Patch Set: Guard macros Created 4 years, 1 month 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 | « no previous file | no next file » | 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 PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 5 #ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 6 #define PDFIUM_THIRD_PARTY_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
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 "safe_conversions.h"
18 #include "third_party/base/macros.h" 17 #include "third_party/base/macros.h"
18 #include "third_party/base/numerics/safe_conversions.h"
19 19
20 namespace pdfium { 20 namespace pdfium {
21 namespace base { 21 namespace base {
22 namespace internal { 22 namespace internal {
23 23
24 // Everything from here up to the floating point operations is portable C++, 24 // Everything from here up to the floating point operations is portable C++,
25 // but it may not be fast. This code could be split based on 25 // but it may not be fast. This code could be split based on
26 // platform/architecture and replaced with potentially faster implementations. 26 // platform/architecture and replaced with potentially faster implementations.
27 27
28 // Integer promotion templates used by the portable checked integer arithmetic. 28 // Integer promotion templates used by the portable checked integer arithmetic.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 std::numeric_limits<Integer>::is_signed>::type>::type type; 88 std::numeric_limits<Integer>::is_signed>::type>::type type;
89 }; 89 };
90 90
91 template <typename Integer> 91 template <typename Integer>
92 struct PositionOfSignBit { 92 struct PositionOfSignBit {
93 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, 93 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
94 size_t>::type value = 94 size_t>::type value =
95 CHAR_BIT * sizeof(Integer) - 1; 95 CHAR_BIT * sizeof(Integer) - 1;
96 }; 96 };
97 97
98 // This is used for UnsignedAbs, where we need to support floating-point
99 // template instantiations even though we don't actually support the operations.
100 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
101 // so the float versions will not compile.
102 template <typename Numeric,
103 bool IsInteger = std::numeric_limits<Numeric>::is_integer,
104 bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
105 struct UnsignedOrFloatForSize;
106
107 template <typename Numeric>
108 struct UnsignedOrFloatForSize<Numeric, true, false> {
109 typedef typename UnsignedIntegerForSize<Numeric>::type type;
110 };
111
112 template <typename Numeric>
113 struct UnsignedOrFloatForSize<Numeric, false, true> {
114 typedef Numeric type;
115 };
116
98 // Helper templates for integer manipulations. 117 // Helper templates for integer manipulations.
99 118
100 template <typename T> 119 template <typename T>
101 constexpr bool HasSignBit(T x) { 120 constexpr bool HasSignBit(T x) {
102 // Cast to unsigned since right shift on signed is undefined. 121 // Cast to unsigned since right shift on signed is undefined.
103 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> 122 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
104 PositionOfSignBit<T>::value); 123 PositionOfSignBit<T>::value);
105 } 124 }
106 125
107 // This wrapper undoes the standard integer promotions. 126 // This wrapper undoes the standard integer promotions.
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 int>::type = 0) { 250 int>::type = 0) {
232 if (y == 0) { 251 if (y == 0) {
233 *validity = RANGE_INVALID; 252 *validity = RANGE_INVALID;
234 return static_cast<T>(0); 253 return static_cast<T>(0);
235 } 254 }
236 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && 255 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
237 y == static_cast<T>(-1)) { 256 y == static_cast<T>(-1)) {
238 *validity = RANGE_OVERFLOW; 257 *validity = RANGE_OVERFLOW;
239 return std::numeric_limits<T>::min(); 258 return std::numeric_limits<T>::min();
240 } 259 }
260
241 *validity = RANGE_VALID; 261 *validity = RANGE_VALID;
242 return static_cast<T>(x / y); 262 return static_cast<T>(x / y);
243 } 263 }
244 264
245 template <typename T> 265 template <typename T>
246 typename std::enable_if<std::numeric_limits<T>::is_integer && 266 typename std::enable_if<std::numeric_limits<T>::is_integer &&
247 std::numeric_limits<T>::is_signed, 267 std::numeric_limits<T>::is_signed,
248 T>::type 268 T>::type
249 CheckedMod(T x, T y, RangeConstraint* validity) { 269 CheckedMod(T x, T y, RangeConstraint* validity) {
250 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; 270 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
(...skipping 10 matching lines...) Expand all
261 } 281 }
262 282
263 template <typename T> 283 template <typename T>
264 typename std::enable_if<std::numeric_limits<T>::is_integer && 284 typename std::enable_if<std::numeric_limits<T>::is_integer &&
265 std::numeric_limits<T>::is_signed, 285 std::numeric_limits<T>::is_signed,
266 T>::type 286 T>::type
267 CheckedNeg(T value, RangeConstraint* validity) { 287 CheckedNeg(T value, RangeConstraint* validity) {
268 *validity = 288 *validity =
269 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 289 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
270 // The negation of signed min is min, so catch that one. 290 // The negation of signed min is min, so catch that one.
271 return -value; 291 return static_cast<T>(*validity == RANGE_VALID ? -value : 0);
272 } 292 }
273 293
274 template <typename T> 294 template <typename T>
275 typename std::enable_if<std::numeric_limits<T>::is_integer && 295 typename std::enable_if<std::numeric_limits<T>::is_integer &&
276 !std::numeric_limits<T>::is_signed, 296 !std::numeric_limits<T>::is_signed,
277 T>::type 297 T>::type
278 CheckedNeg(T value, RangeConstraint* validity) { 298 CheckedNeg(T value, RangeConstraint* validity) {
279 // The only legal unsigned negation is zero. 299 // The only legal unsigned negation is zero.
280 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; 300 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
281 return static_cast<T>( 301 return static_cast<T>(
282 -static_cast<typename SignedIntegerForSize<T>::type>(value)); 302 *validity == RANGE_VALID
303 ? -static_cast<typename SignedIntegerForSize<T>::type>(value)
304 : 0);
283 } 305 }
284 306
285 template <typename T> 307 template <typename T>
286 typename std::enable_if<std::numeric_limits<T>::is_integer && 308 typename std::enable_if<std::numeric_limits<T>::is_integer &&
287 std::numeric_limits<T>::is_signed, 309 std::numeric_limits<T>::is_signed,
288 T>::type 310 T>::type
289 CheckedAbs(T value, RangeConstraint* validity) { 311 CheckedAbs(T value, RangeConstraint* validity) {
290 *validity = 312 *validity =
291 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 313 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
292 return std::abs(value); 314 return static_cast<T>(*validity == RANGE_VALID ? std::abs(value) : 0);
293 } 315 }
294 316
295 template <typename T> 317 template <typename T>
296 typename std::enable_if<std::numeric_limits<T>::is_integer && 318 typename std::enable_if<std::numeric_limits<T>::is_integer &&
297 !std::numeric_limits<T>::is_signed, 319 !std::numeric_limits<T>::is_signed,
298 T>::type 320 T>::type
299 CheckedAbs(T value, RangeConstraint* validity) { 321 CheckedAbs(T value, RangeConstraint* validity) {
300 // Absolute value of a positive is just its identiy. 322 // T is unsigned, so |value| must already be positive.
301 *validity = RANGE_VALID; 323 *validity = RANGE_VALID;
302 return value; 324 return value;
303 } 325 }
304 326
327 template <typename T>
328 typename std::enable_if<std::numeric_limits<T>::is_integer &&
329 std::numeric_limits<T>::is_signed,
330 typename UnsignedIntegerForSize<T>::type>::type
331 CheckedUnsignedAbs(T value) {
332 typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
333 return value == std::numeric_limits<T>::min()
334 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
335 : static_cast<UnsignedT>(std::abs(value));
336 }
337
338 template <typename T>
339 typename std::enable_if<std::numeric_limits<T>::is_integer &&
340 !std::numeric_limits<T>::is_signed,
341 T>::type
342 CheckedUnsignedAbs(T value) {
343 // T is unsigned, so |value| must already be positive.
344 return static_cast<T>(value);
345 }
346
305 // These are the floating point stubs that the compiler needs to see. Only the 347 // These are the floating point stubs that the compiler needs to see. Only the
306 // negation operation is ever called. 348 // negation operation is ever called.
307 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ 349 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
308 template <typename T> \ 350 template <typename T> \
309 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ 351 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
310 Checked##NAME(T, T, RangeConstraint*) { \ 352 Checked##NAME(T, T, RangeConstraint*) { \
311 NOTREACHED(); \ 353 NOTREACHED(); \
312 return static_cast<T>(0); \ 354 return static_cast<T>(0); \
313 } 355 }
314 356
315 BASE_FLOAT_ARITHMETIC_STUBS(Add) 357 BASE_FLOAT_ARITHMETIC_STUBS(Add)
316 BASE_FLOAT_ARITHMETIC_STUBS(Sub) 358 BASE_FLOAT_ARITHMETIC_STUBS(Sub)
317 BASE_FLOAT_ARITHMETIC_STUBS(Mul) 359 BASE_FLOAT_ARITHMETIC_STUBS(Mul)
318 BASE_FLOAT_ARITHMETIC_STUBS(Div) 360 BASE_FLOAT_ARITHMETIC_STUBS(Div)
319 BASE_FLOAT_ARITHMETIC_STUBS(Mod) 361 BASE_FLOAT_ARITHMETIC_STUBS(Mod)
320 362
321 #undef BASE_FLOAT_ARITHMETIC_STUBS 363 #undef BASE_FLOAT_ARITHMETIC_STUBS
322 364
323 template <typename T> 365 template <typename T>
324 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( 366 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
325 T value, 367 T value,
326 RangeConstraint*) { 368 RangeConstraint*) {
327 return -value; 369 return static_cast<T>(-value);
328 } 370 }
329 371
330 template <typename T> 372 template <typename T>
331 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( 373 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
332 T value, 374 T value,
333 RangeConstraint*) { 375 RangeConstraint*) {
334 return std::abs(value); 376 return static_cast<T>(std::abs(value));
335 } 377 }
336 378
337 // Floats carry around their validity state with them, but integers do not. So, 379 // Floats carry around their validity state with them, but integers do not. So,
338 // we wrap the underlying value in a specialization in order to hide that detail 380 // we wrap the underlying value in a specialization in order to hide that detail
339 // and expose an interface via accessors. 381 // and expose an interface via accessors.
340 enum NumericRepresentation { 382 enum NumericRepresentation {
341 NUMERIC_INTEGER, 383 NUMERIC_INTEGER,
342 NUMERIC_FLOATING, 384 NUMERIC_FLOATING,
343 NUMERIC_UNKNOWN 385 NUMERIC_UNKNOWN
344 }; 386 };
345 387
346 template <typename NumericType> 388 template <typename NumericType>
347 struct GetNumericRepresentation { 389 struct GetNumericRepresentation {
348 static const NumericRepresentation value = 390 static const NumericRepresentation value =
349 std::numeric_limits<NumericType>::is_integer 391 std::numeric_limits<NumericType>::is_integer
350 ? NUMERIC_INTEGER 392 ? NUMERIC_INTEGER
351 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING 393 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
352 : NUMERIC_UNKNOWN); 394 : NUMERIC_UNKNOWN);
353 }; 395 };
354 396
355 template <typename T, NumericRepresentation type = 397 template <typename T, NumericRepresentation type =
356 GetNumericRepresentation<T>::value> 398 GetNumericRepresentation<T>::value>
357 class CheckedNumericState {}; 399 class CheckedNumericState {};
358 400
359 // Integrals require quite a bit of additional housekeeping to manage state. 401 // Integrals require quite a bit of additional housekeeping to manage state.
360 template <typename T> 402 template <typename T>
361 class CheckedNumericState<T, NUMERIC_INTEGER> { 403 class CheckedNumericState<T, NUMERIC_INTEGER> {
362 private: 404 private:
363 T value_; 405 T value_;
364 RangeConstraint validity_; 406 RangeConstraint validity_ : CHAR_BIT; // Actually requires only two bits.
365 407
366 public: 408 public:
367 template <typename Src, NumericRepresentation type> 409 template <typename Src, NumericRepresentation type>
368 friend class CheckedNumericState; 410 friend class CheckedNumericState;
369 411
370 CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} 412 CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
371 413
372 template <typename Src> 414 template <typename Src>
373 CheckedNumericState(Src value, RangeConstraint validity) 415 CheckedNumericState(Src value, RangeConstraint validity)
374 : value_(value), 416 : value_(static_cast<T>(value)),
375 validity_(GetRangeConstraint(validity | 417 validity_(GetRangeConstraint(validity |
376 DstRangeRelationToSrcRange<T>(value))) { 418 DstRangeRelationToSrcRange<T>(value))) {
377 COMPILE_ASSERT(std::numeric_limits<Src>::is_specialized, 419 static_assert(std::numeric_limits<Src>::is_specialized,
378 argument_must_be_numeric); 420 "Argument must be numeric.");
379 } 421 }
380 422
381 // Copy constructor. 423 // Copy constructor.
382 template <typename Src> 424 template <typename Src>
383 CheckedNumericState(const CheckedNumericState<Src>& rhs) 425 CheckedNumericState(const CheckedNumericState<Src>& rhs)
384 : value_(static_cast<T>(rhs.value())), 426 : value_(static_cast<T>(rhs.value())),
385 validity_(GetRangeConstraint( 427 validity_(GetRangeConstraint(
386 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} 428 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
387 429
388 template <typename Src> 430 template <typename Src>
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 CheckedNumericState(const CheckedNumericState<Src>& rhs) 491 CheckedNumericState(const CheckedNumericState<Src>& rhs)
450 : value_(static_cast<T>(rhs.value())) {} 492 : value_(static_cast<T>(rhs.value())) {}
451 493
452 RangeConstraint validity() const { 494 RangeConstraint validity() const {
453 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), 495 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
454 value_ >= -std::numeric_limits<T>::max()); 496 value_ >= -std::numeric_limits<T>::max());
455 } 497 }
456 T value() const { return value_; } 498 T value() const { return value_; }
457 }; 499 };
458 500
459 // For integers less than 128-bit and floats 32-bit or larger, we can distil 501 // For integers less than 128-bit and floats 32-bit or larger, we have the type
460 // C/C++ arithmetic promotions down to two simple rules: 502 // with the larger maximum exponent take precedence.
461 // 1. The type with the larger maximum exponent always takes precedence. 503 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
462 // 2. The resulting type must be promoted to at least an int.
463 // The following template specializations implement that promotion logic.
464 enum ArithmeticPromotionCategory {
465 LEFT_PROMOTION,
466 RIGHT_PROMOTION,
467 DEFAULT_PROMOTION
468 };
469 504
470 template <typename Lhs, 505 template <typename Lhs,
471 typename Rhs = Lhs, 506 typename Rhs = Lhs,
472 ArithmeticPromotionCategory Promotion = 507 ArithmeticPromotionCategory Promotion =
473 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) 508 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
474 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value 509 ? LEFT_PROMOTION
475 ? LEFT_PROMOTION 510 : RIGHT_PROMOTION>
476 : DEFAULT_PROMOTION)
477 : (MaxExponent<Rhs>::value > MaxExponent<int>::value
478 ? RIGHT_PROMOTION
479 : DEFAULT_PROMOTION) >
480 struct ArithmeticPromotion; 511 struct ArithmeticPromotion;
481 512
482 template <typename Lhs, typename Rhs> 513 template <typename Lhs, typename Rhs>
483 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { 514 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
484 typedef Lhs type; 515 typedef Lhs type;
485 }; 516 };
486 517
487 template <typename Lhs, typename Rhs> 518 template <typename Lhs, typename Rhs>
488 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { 519 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
489 typedef Rhs type; 520 typedef Rhs type;
490 }; 521 };
491 522
492 template <typename Lhs, typename Rhs>
493 struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
494 typedef int type;
495 };
496
497 // We can statically check if operations on the provided types can wrap, so we 523 // We can statically check if operations on the provided types can wrap, so we
498 // can skip the checked operations if they're not needed. So, for an integer we 524 // can skip the checked operations if they're not needed. So, for an integer we
499 // care if the destination type preserves the sign and is twice the width of 525 // care if the destination type preserves the sign and is twice the width of
500 // the source. 526 // the source.
501 template <typename T, typename Lhs, typename Rhs> 527 template <typename T, typename Lhs, typename Rhs>
502 struct IsIntegerArithmeticSafe { 528 struct IsIntegerArithmeticSafe {
503 static const bool value = !std::numeric_limits<T>::is_iec559 && 529 static const bool value = !std::numeric_limits<T>::is_iec559 &&
504 StaticDstRangeRelationToSrcRange<T, Lhs>::value == 530 StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
505 NUMERIC_RANGE_CONTAINED && 531 NUMERIC_RANGE_CONTAINED &&
506 sizeof(T) >= (2 * sizeof(Lhs)) && 532 sizeof(T) >= (2 * sizeof(Lhs)) &&
507 StaticDstRangeRelationToSrcRange<T, Rhs>::value != 533 StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
508 NUMERIC_RANGE_CONTAINED && 534 NUMERIC_RANGE_CONTAINED &&
509 sizeof(T) >= (2 * sizeof(Rhs)); 535 sizeof(T) >= (2 * sizeof(Rhs));
510 }; 536 };
511 537
512 } // namespace internal 538 } // namespace internal
513 } // namespace base 539 } // namespace base
514 } // namespace pdfium 540 } // namespace pdfium
515 541
516 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 542 #endif // PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698