OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef SAFE_MATH_IMPL_H_ |
| 6 #define SAFE_MATH_IMPL_H_ |
| 7 |
| 8 #include <stdint.h> |
| 9 |
| 10 #include <limits> |
| 11 |
| 12 #include "base/compiler_specific.h" |
| 13 #include "base/macros.h" |
| 14 |
| 15 namespace base { |
| 16 namespace internal { |
| 17 |
| 18 using std::numeric_limits; |
| 19 |
| 20 // Everything from here up to the definition of CheckedNumericState is |
| 21 // portable C++, but it may not be fast. This code could be split based on |
| 22 // platform/architecture and replaced with potentially faster implementations. |
| 23 |
| 24 template <size_t Size, bool IsSigned> |
| 25 struct IntegerTypeForSizeAndSign {}; |
| 26 |
| 27 template <> |
| 28 struct IntegerTypeForSizeAndSign<1, true> { |
| 29 typedef int8_t Type; |
| 30 }; |
| 31 |
| 32 template <> |
| 33 struct IntegerTypeForSizeAndSign<1, false> { |
| 34 typedef uint8_t Type; |
| 35 }; |
| 36 |
| 37 template <> |
| 38 struct IntegerTypeForSizeAndSign<2, true> { |
| 39 typedef int16_t Type; |
| 40 }; |
| 41 |
| 42 template <> |
| 43 struct IntegerTypeForSizeAndSign<2, false> { |
| 44 typedef uint16_t Type; |
| 45 }; |
| 46 |
| 47 template <> |
| 48 struct IntegerTypeForSizeAndSign<4, true> { |
| 49 typedef int32_t Type; |
| 50 }; |
| 51 |
| 52 template <> |
| 53 struct IntegerTypeForSizeAndSign<4, false> { |
| 54 typedef uint32_t Type; |
| 55 }; |
| 56 |
| 57 template <> |
| 58 struct IntegerTypeForSizeAndSign<8, true> { |
| 59 typedef int64_t Type; |
| 60 }; |
| 61 |
| 62 template <> |
| 63 struct IntegerTypeForSizeAndSign<8, false> { |
| 64 typedef uint64_t Type; |
| 65 }; |
| 66 |
| 67 // This is effectively a compile assert to ensure we're supporting the full |
| 68 // type range for this compiler (otherwise multiply may not compile). |
| 69 typedef IntegerTypeForSizeAndSign<sizeof(intmax_t), true> MaxSupportedInteger; |
| 70 |
| 71 template <typename IntegerType> |
| 72 struct UnsignedType { |
| 73 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), false>::Type |
| 74 Type; |
| 75 }; |
| 76 |
| 77 template <typename IntegerType> |
| 78 struct SignedType { |
| 79 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), true>::Type |
| 80 Type; |
| 81 }; |
| 82 |
| 83 template <typename IntegerType> |
| 84 struct TwiceWiderType { |
| 85 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType) * 2, |
| 86 numeric_limits<IntegerType>::is_signed>::Type |
| 87 Type; |
| 88 }; |
| 89 |
| 90 template <typename IntegerType> |
| 91 struct PositionOfSignBit { |
| 92 static const size_t value = 8 * sizeof(IntegerType) - 1; |
| 93 }; |
| 94 |
| 95 |
| 96 template <typename T> |
| 97 bool HasSignBit(T x) { |
| 98 // Cast to unsigned since right shift on signed is undefined. |
| 99 return !!(static_cast<typename UnsignedType<T>::Type>(x) >> |
| 100 PositionOfSignBit<T>::value); |
| 101 } |
| 102 |
| 103 |
| 104 // This wrapper undoes the standard integer promotions. |
| 105 template <typename T> |
| 106 T BinaryComplement(T x) { |
| 107 return ~x; |
| 108 } |
| 109 |
| 110 template <typename T, |
| 111 DstSignId DstSign = numeric_limits<T>::is_signed ? |
| 112 DST_SIGNED : DST_UNSIGNED> |
| 113 struct NegIntegerImpl; |
| 114 |
| 115 template <typename T> |
| 116 struct NegIntegerImpl<T, DST_SIGNED> { |
| 117 static RangeCheckId run(T value, T* result) { |
| 118 *result = -value; |
| 119 // The negation of signed min is min, so catch that one. |
| 120 return value != numeric_limits<T>::min() ? TYPE_VALID : TYPE_OVERFLOW; |
| 121 } |
| 122 }; |
| 123 |
| 124 template <typename T> |
| 125 struct NegIntegerImpl<T, DST_UNSIGNED> { |
| 126 static RangeCheckId run(T value, T* result) { |
| 127 *result = static_cast<T>( |
| 128 -static_cast<typename SignedType<T>::Type>(value)); |
| 129 // The only legal unsigned negation is zero. |
| 130 return *result ? TYPE_UNDERFLOW : TYPE_VALID; |
| 131 } |
| 132 }; |
| 133 |
| 134 template <typename T> |
| 135 RangeCheckId NegInteger(T value, T* result) { |
| 136 return NegIntegerImpl<T>::run(value, result); |
| 137 } |
| 138 |
| 139 |
| 140 template <typename T> |
| 141 RangeCheckId AddIntegers(T x, T y, T* result) { |
| 142 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers); |
| 143 // Since the value of x+y is undefined if we have a signed type, we compute |
| 144 // it using the unsigned type of the same size. |
| 145 typedef typename UnsignedType<T>::Type UnsignedDst; |
| 146 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 147 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 148 UnsignedDst uresult = ux + uy; |
| 149 *result = static_cast<T>(uresult); |
| 150 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 151 // that of y. |
| 152 if (numeric_limits<T>::is_signed) { |
| 153 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) |
| 154 return TYPE_VALID; |
| 155 // Direction of wrap is inverse of result sign. |
| 156 return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW; |
| 157 } |
| 158 // Unsigned is either valid or overflow. |
| 159 return BinaryComplement(x) >= y ? TYPE_VALID : TYPE_OVERFLOW; |
| 160 } |
| 161 |
| 162 template <typename T> |
| 163 RangeCheckId SubIntegers(T x, T y, T* result) { |
| 164 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers); |
| 165 // Since the value of x+y is undefined if we have a signed type, we compute |
| 166 // it using the unsigned type of the same size. |
| 167 typedef typename UnsignedType<T>::Type UnsignedDst; |
| 168 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 169 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 170 UnsignedDst uresult = ux - uy; |
| 171 *result = static_cast<T>(uresult); |
| 172 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 173 // the same sign. |
| 174 if (numeric_limits<T>::is_signed) { |
| 175 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) |
| 176 return TYPE_VALID; |
| 177 // Direction of wrap is inverse of result sign. |
| 178 return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW; |
| 179 } |
| 180 // Unsigned is either valid or underflow. |
| 181 return x >= y ? TYPE_VALID : TYPE_UNDERFLOW; |
| 182 } |
| 183 |
| 184 // Integer multiplication is a bit complicated. In the fast case we just |
| 185 // we just promote to a twice wider type, and range check the result. In the |
| 186 // slow case we need to manually check that the result won't be truncated by |
| 187 // checking with division against the appropriate bound. |
| 188 enum IntegerMathId { |
| 189 FAST_MATH, |
| 190 SLOW_MATH |
| 191 }; |
| 192 template <typename T, |
| 193 DstSignId DstSign = numeric_limits<T>::is_signed ? |
| 194 DST_SIGNED : DST_UNSIGNED, |
| 195 IntegerMathId MathType = sizeof(T)* 2 <= sizeof(uintmax_t) ? |
| 196 FAST_MATH : SLOW_MATH> |
| 197 struct MulIntegersImpl {}; |
| 198 |
| 199 template <typename T, DstSignId DstSign> |
| 200 struct MulIntegersImpl<T, DstSign, FAST_MATH> { |
| 201 static RangeCheckId run(T x, T y, T* result) { |
| 202 typedef typename TwiceWiderType<T>::Type IntermediateType; |
| 203 IntermediateType tmp = static_cast<IntermediateType>(x) * |
| 204 static_cast<IntermediateType>(y); |
| 205 *result = static_cast<T>(tmp); |
| 206 return RangeCheck<T>(tmp); |
| 207 } |
| 208 }; |
| 209 |
| 210 template <typename T> |
| 211 struct MulIntegersImpl<T, DST_SIGNED, SLOW_MATH> { |
| 212 static RangeCheckId run(T x, T y, T* result) { |
| 213 *result = x * y; |
| 214 |
| 215 // if either side is zero then the result will be zero. |
| 216 if (!(x || y)) |
| 217 return TYPE_VALID; |
| 218 |
| 219 // Check each boundary based on the sign. |
| 220 if (x > 0) { |
| 221 if (y > 0) |
| 222 return x <= numeric_limits<T>::max() / y ? TYPE_VALID : TYPE_OVERFLOW; |
| 223 return y >= numeric_limits<T>::min() / x ? TYPE_VALID : TYPE_UNDERFLOW; |
| 224 } |
| 225 |
| 226 if (y > 0) |
| 227 return x >= numeric_limits<T>::min() / y ? TYPE_VALID : TYPE_UNDERFLOW; |
| 228 return y >= numeric_limits<T>::max() / x ? TYPE_VALID : TYPE_OVERFLOW; |
| 229 } |
| 230 }; |
| 231 |
| 232 template <typename T> |
| 233 struct MulIntegersImpl<T, DST_UNSIGNED, SLOW_MATH> { |
| 234 static RangeCheckId run(T x, T y, T* result) { |
| 235 *result = x * y; |
| 236 return (y == 0 || x <= numeric_limits<T>::max() / y) ? |
| 237 TYPE_VALID : TYPE_OVERFLOW; |
| 238 } |
| 239 }; |
| 240 |
| 241 template <typename T> |
| 242 RangeCheckId MulIntegers(T x, T y, T* result) { |
| 243 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers); |
| 244 return MulIntegersImpl<T>::run(x, y, result); |
| 245 } |
| 246 |
| 247 |
| 248 // Division is really easy. Just check for an invalid negation on signed min/-1. |
| 249 template <typename T> |
| 250 RangeCheckId DivIntegers(T x, T y, T* result) { |
| 251 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers); |
| 252 *result = x / y; |
| 253 return (!numeric_limits<T>::is_signed || x != numeric_limits<T>::min() |
| 254 || y != -1) ? TYPE_VALID : TYPE_OVERFLOW; |
| 255 } |
| 256 |
| 257 // Modulus is easy, but we split it into signed and unsigned to avoid warnings. |
| 258 template <typename T, |
| 259 DstSignId DstSign = numeric_limits<T>::is_signed ? |
| 260 DST_SIGNED : DST_UNSIGNED> |
| 261 struct ModIntegersImpl {}; |
| 262 |
| 263 template <typename T> |
| 264 struct ModIntegersImpl<T, DST_SIGNED> { |
| 265 static RangeCheckId run(T x, T y, T* result) { |
| 266 *result = x % y; |
| 267 return y > 0 ? TYPE_VALID : TYPE_INVALID; |
| 268 } |
| 269 }; |
| 270 |
| 271 template <typename T> |
| 272 struct ModIntegersImpl<T, DST_UNSIGNED> { |
| 273 static RangeCheckId run(T x, T y, T* result) { |
| 274 *result = x % y; |
| 275 return TYPE_VALID; |
| 276 } |
| 277 }; |
| 278 |
| 279 template <typename T> |
| 280 RangeCheckId ModIntegers(T x, T y, T* result) { |
| 281 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers); |
| 282 return ModIntegersImpl<T>::run(x, y, result); |
| 283 } |
| 284 |
| 285 |
| 286 // Floats carry around their validity state with them, but integers do not. So, |
| 287 // we wrap the underlying value in a specialization in order to hide that detail |
| 288 // and expose an interface via accessors. |
| 289 enum NumericTypeId { |
| 290 NUMERIC_INTEGER, |
| 291 NUMERIC_FLOATING, |
| 292 NUMERIC_UNKNOWN |
| 293 }; |
| 294 |
| 295 template <typename NumericType> |
| 296 struct GetNumericTypeId { |
| 297 static const NumericTypeId value = numeric_limits<NumericType>::is_integer ? |
| 298 NUMERIC_INTEGER : (numeric_limits<NumericType>::is_iec559 ? |
| 299 NUMERIC_FLOATING : NUMERIC_UNKNOWN); |
| 300 }; |
| 301 |
| 302 template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value> |
| 303 class CheckedNumericState {}; |
| 304 |
| 305 // Integrals require quite a bit of additional housekeeping to manage state. |
| 306 template <typename T> |
| 307 class CheckedNumericState<T, NUMERIC_INTEGER> { |
| 308 private: |
| 309 T value_; |
| 310 RangeCheckId validity_; |
| 311 |
| 312 public: |
| 313 template <typename Src, NumericTypeId Type> |
| 314 friend class CheckedNumericState; |
| 315 |
| 316 CheckedNumericState() : value_(0), validity_(TYPE_VALID) {} |
| 317 |
| 318 template <typename Src> |
| 319 CheckedNumericState(Src value, RangeCheckId validity) : |
| 320 value_(value), validity_(static_cast<RangeCheckId>( |
| 321 validity | RangeCheck<T>(value))) { |
| 322 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 323 argument_must_be_numeric); |
| 324 } |
| 325 |
| 326 template <typename Src> |
| 327 explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) : |
| 328 value_(static_cast<T>(rhs.value_)), validity_( |
| 329 static_cast<RangeCheckId>(rhs.validity() | |
| 330 RangeCheck<T>(rhs.value_))) { |
| 331 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 332 argument_must_be_numeric); |
| 333 } |
| 334 |
| 335 template <typename Src> |
| 336 explicit CheckedNumericState(Src value) : |
| 337 value_(static_cast<T>(value)), validity_(RangeCheck<T>(value)) { |
| 338 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 339 argument_must_be_numeric); |
| 340 } |
| 341 |
| 342 RangeCheckId validity() const { return validity_; } |
| 343 T value() const { return value_; } |
| 344 }; |
| 345 |
| 346 // Floating points maintain their own validity, but need translation wrappers. |
| 347 template <typename T> |
| 348 class CheckedNumericState<T, NUMERIC_FLOATING> { |
| 349 private: |
| 350 T value_; |
| 351 |
| 352 public: |
| 353 template <typename Src, NumericTypeId Type> |
| 354 friend class CheckedNumericState; |
| 355 |
| 356 CheckedNumericState() : value_(0.0) {} |
| 357 |
| 358 template <typename Src> |
| 359 CheckedNumericState(Src value, RangeCheckId validity) { |
| 360 // A non-integer specialization can get generated in non-optimized builds, |
| 361 // but it should be impossible to trigger the code path. |
| 362 DCHECK(numeric_limits<Src>::is_integer); |
| 363 |
| 364 switch (RangeCheck<T>(value)) { |
| 365 case TYPE_VALID: |
| 366 value_ = static_cast<T>(value_); |
| 367 break; |
| 368 |
| 369 case TYPE_UNDERFLOW: |
| 370 value_ = -numeric_limits<T>::infinity(); |
| 371 break; |
| 372 |
| 373 case TYPE_OVERFLOW: |
| 374 value_ = numeric_limits<T>::infinity(); |
| 375 break; |
| 376 |
| 377 case TYPE_INVALID: |
| 378 value_ = numeric_limits<T>::quiet_NaN(); |
| 379 break; |
| 380 |
| 381 default: |
| 382 NOTREACHED(); |
| 383 } |
| 384 } |
| 385 |
| 386 template <typename Src> |
| 387 explicit CheckedNumericState(Src value) : value_(static_cast<T>(value)) { |
| 388 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 389 argument_must_be_numeric); |
| 390 } |
| 391 |
| 392 template <typename Src> |
| 393 explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) : |
| 394 value_(static_cast<T>(rhs.value_)) { |
| 395 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 396 argument_must_be_numeric); |
| 397 } |
| 398 |
| 399 RangeCheckId validity() const { |
| 400 return BASE_NUMERIC_RANGE_CHECK_RESULT( |
| 401 value_ < numeric_limits<T>::max(), |
| 402 value_ > -numeric_limits<T>::max()); |
| 403 } |
| 404 T value() const { return value_; } |
| 405 }; |
| 406 |
| 407 // In addition to wrapping the state, we also need to wrap all the arithmetic |
| 408 // operations because we use a fast path for floating points, but a slower, |
| 409 // checked path for integers. |
| 410 template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value> |
| 411 class CheckedIntegerArithmetic {}; |
| 412 |
| 413 // Wrap the checked integer operations injected as a dependency. |
| 414 template <typename T> |
| 415 class CheckedIntegerArithmetic<T, NUMERIC_INTEGER> { |
| 416 public: |
| 417 static RangeCheckId Neg(T value, T* result) { |
| 418 return NegInteger(value, result); |
| 419 } |
| 420 static RangeCheckId Add(T x, T y, T* result) { |
| 421 return AddIntegers(x, y, result); |
| 422 } |
| 423 static RangeCheckId Sub(T x, T y, T* result) { |
| 424 return SubIntegers(x, y, result); |
| 425 } |
| 426 static RangeCheckId Mul(T x, T y, T* result) { |
| 427 return MulIntegers(x, y, result); |
| 428 } |
| 429 static RangeCheckId Div(T x, T y, T* result) { |
| 430 return DivIntegers(x, y, result); |
| 431 } |
| 432 static RangeCheckId Mod(T x, T y, T* result) { |
| 433 return ModIntegers(x, y, result); |
| 434 } |
| 435 }; |
| 436 |
| 437 // We never use these for floats, but the compiler needs to see an |
| 438 // implementation. |
| 439 template <typename T> |
| 440 class CheckedIntegerArithmetic<T, NUMERIC_FLOATING> { |
| 441 private: |
| 442 static RangeCheckId not_implemented() { |
| 443 NOTREACHED(); |
| 444 return TYPE_INVALID; |
| 445 } |
| 446 |
| 447 public: |
| 448 static RangeCheckId Add(T, T, T*) { return not_implemented(); } |
| 449 static RangeCheckId Sub(T, T, T*) { return not_implemented(); } |
| 450 static RangeCheckId Mul(T, T, T*) { return not_implemented(); } |
| 451 static RangeCheckId Div(T, T, T*) { return not_implemented(); } |
| 452 static RangeCheckId Mod(T, T, T*) { return not_implemented(); } |
| 453 static RangeCheckId Neg(T, T*) { return not_implemented(); } |
| 454 }; |
| 455 |
| 456 |
| 457 // This template class implements all the logic and operators for safe numeric |
| 458 // arithmetic and conversions. |
| 459 template <typename T> |
| 460 class CheckedNumeric { |
| 461 private: |
| 462 CheckedNumericState<T> state_; |
| 463 |
| 464 public: |
| 465 template <typename Src> |
| 466 friend class CheckedNumeric; |
| 467 |
| 468 CheckedNumeric() {} |
| 469 |
| 470 template <typename Src> |
| 471 CheckedNumeric(const CheckedNumeric<Src>& rhs) : state_(rhs.state_) {} |
| 472 |
| 473 template <typename Src> |
| 474 CheckedNumeric(Src value, RangeCheckId validity) : state_(value, validity) {} |
| 475 |
| 476 template <typename Src> |
| 477 CheckedNumeric(Src value) : state_(value) {} |
| 478 |
| 479 RangeCheckId validity() const { return state_.validity(); } |
| 480 bool IsValid() const { return validity() == TYPE_VALID; } |
| 481 bool IsOverflow() const { return validity() == TYPE_OVERFLOW; } |
| 482 bool IsUnderflow() const { return validity() == TYPE_UNDERFLOW; } |
| 483 bool IsInvalid() const { return validity() == TYPE_INVALID; } |
| 484 |
| 485 T ValueUnsafe() const { return state_.value(); } |
| 486 |
| 487 template <typename FloatingType> |
| 488 FloatingType ValueFloating() const { |
| 489 if (std::numeric_limits<T>::is_iec559) |
| 490 return ValueUnsafe(); |
| 491 return CheckedNumeric<FloatingType>(ValueUnsafe()).ValueUnsafe(); |
| 492 } |
| 493 |
| 494 T ValueOrDie() const { |
| 495 CHECK(IsValid()); |
| 496 return state_.value(); |
| 497 } |
| 498 |
| 499 T ValueOrDefault(T default_value) const { |
| 500 return IsValid() ? state_.value() : default_value; |
| 501 } |
| 502 |
| 503 // Friend all the operator overloads |
| 504 template <typename Src> |
| 505 CheckedNumeric& operator +=(Src rhs); |
| 506 |
| 507 template <typename Src> |
| 508 CheckedNumeric& operator -=(Src rhs); |
| 509 |
| 510 template <typename Src> |
| 511 CheckedNumeric& operator *=(Src rhs); |
| 512 |
| 513 template <typename Src> |
| 514 CheckedNumeric& operator /=(Src rhs); |
| 515 |
| 516 template <typename Src> |
| 517 CheckedNumeric& operator %=(Src rhs); |
| 518 |
| 519 CheckedNumeric operator -() const { |
| 520 // Negation is always valid for floating point |
| 521 if (numeric_limits<T>::is_iec559) |
| 522 return -state_.value(); |
| 523 |
| 524 T value; |
| 525 RangeCheckId validity = static_cast<RangeCheckId>( |
| 526 state_.validity() | |
| 527 CheckedIntegerArithmetic<T>::Neg(state_.value(), &value)); |
| 528 return CheckedNumeric<T>(value, validity); |
| 529 } |
| 530 |
| 531 CheckedNumeric& operator++() { |
| 532 *this += 1; |
| 533 return *this; |
| 534 } |
| 535 |
| 536 CheckedNumeric operator++(int) { |
| 537 CheckedNumeric tmp = *this; |
| 538 *this += 1; |
| 539 return tmp; |
| 540 } |
| 541 |
| 542 CheckedNumeric& operator--() { |
| 543 *this -= 1; |
| 544 return *this; |
| 545 } |
| 546 |
| 547 CheckedNumeric operator--(int) { |
| 548 CheckedNumeric tmp = *this; |
| 549 *this -= 1; |
| 550 return tmp; |
| 551 } |
| 552 |
| 553 // These static functions behave like a convenience operator for casting to |
| 554 // the desired numeric base type or CheckedNumeric type. As an optimization, |
| 555 // a reference is returned when Src is the same type as T. |
| 556 template <typename Src> |
| 557 CheckedNumeric<T> static cast(Src u) { |
| 558 COMPILE_ASSERT(numeric_limits<Src>::is_specialized, |
| 559 argument_must_be_numeric); |
| 560 return u; |
| 561 } |
| 562 |
| 563 template <typename Src> |
| 564 CheckedNumeric<T> static cast(const CheckedNumeric<Src>& u) { |
| 565 return u; |
| 566 } |
| 567 |
| 568 CheckedNumeric<T> static cast(const CheckedNumeric<T>& u) { |
| 569 return u; |
| 570 } |
| 571 }; |
| 572 |
| 573 enum ArithmeticPromotionId { |
| 574 LEFT_PROMOTION, |
| 575 RIGHT_PROMOTION, |
| 576 DEFAULT_PROMOTION |
| 577 }; |
| 578 |
| 579 template <typename Lhs, typename Rhs, |
| 580 ArithmeticPromotionId Promotion = |
| 581 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) ? |
| 582 (MaxExponent<Lhs>::value > MaxExponent<int>::value ? |
| 583 LEFT_PROMOTION : DEFAULT_PROMOTION) : |
| 584 (MaxExponent<Rhs>::value > MaxExponent<int>::value ? |
| 585 RIGHT_PROMOTION : DEFAULT_PROMOTION)> |
| 586 struct ArithmeticPromotion {}; |
| 587 |
| 588 template <typename Lhs, typename Rhs> |
| 589 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
| 590 typedef Lhs Type; |
| 591 }; |
| 592 |
| 593 template <typename Lhs, typename Rhs> |
| 594 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
| 595 typedef Rhs Type; |
| 596 }; |
| 597 |
| 598 template <typename Lhs, typename Rhs> |
| 599 struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> { |
| 600 typedef int Type; |
| 601 }; |
| 602 |
| 603 // Statically check if operations on the provided types can wrap, so we can skip |
| 604 // the checked operations if they're not needed. An integer is safe if the |
| 605 // destination type preserves sign and is wider. |
| 606 template <typename T, typename Lhs, typename Rhs> |
| 607 struct IsIntegerArithmeticSafe { |
| 608 static const bool value = !numeric_limits<T>::is_iec559 && |
| 609 StaticRangeCheck<T, Lhs>::value == CONTAINS_RANGE && |
| 610 sizeof(T) >= (2 * sizeof(Lhs)) && |
| 611 StaticRangeCheck<T, Rhs>::value != CONTAINS_RANGE && |
| 612 sizeof(T) >= (2 * sizeof(Rhs)); |
| 613 }; |
| 614 |
| 615 // This is the boilerplate for the standard arithmetic operator overloads. A |
| 616 // macro isn't the prettiest solution, but it beats rewriting these five times. |
| 617 // Some details worth noting: |
| 618 // * We employ the standard aritmetic promotions. |
| 619 // * We skip the range checking operations for floating points. |
| 620 // * We skip the range checking operations for integers with sufficient range. |
| 621 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME,OP,COMPOUND_OP) \ |
| 622 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ |
| 623 template <typename T> \ |
| 624 CheckedNumeric<typename ArithmeticPromotion<T, T>::Type> \ |
| 625 operator OP(const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) { \ |
| 626 typedef typename ArithmeticPromotion<T, T>::Type Promotion; \ |
| 627 /* Floating point always takes the fast path */ \ |
| 628 if (numeric_limits<T>::is_iec559) \ |
| 629 return CheckedNumeric<T>(lhs.template ValueFloating<T>() OP \ |
| 630 rhs.template ValueFloating<T>()); \ |
| 631 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ |
| 632 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ |
| 633 static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \ |
| 634 T result = 0; \ |
| 635 RangeCheckId validity = \ |
| 636 CheckedIntegerArithmetic<Promotion>::NAME(lhs.ValueUnsafe(), \ |
| 637 rhs.ValueUnsafe(), \ |
| 638 &result); \ |
| 639 return CheckedNumeric<Promotion>(result, static_cast<RangeCheckId>( \ |
| 640 validity | lhs.validity() | rhs.validity())); \ |
| 641 } \ |
| 642 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ |
| 643 template <typename T, typename Src> \ |
| 644 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \ |
| 645 operator OP(const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) { \ |
| 646 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \ |
| 647 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
| 648 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ |
| 649 static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \ |
| 650 return CheckedNumeric<Promotion>::cast(lhs) OP \ |
| 651 CheckedNumeric<Promotion>::cast(rhs); \ |
| 652 } \ |
| 653 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ |
| 654 template <typename T, typename Src> \ |
| 655 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \ |
| 656 operator OP(const CheckedNumeric<T> &lhs, Src rhs) { \ |
| 657 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \ |
| 658 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
| 659 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP \ |
| 660 rhs, lhs.validity()); \ |
| 661 return CheckedNumeric<Promotion>::cast(lhs) OP \ |
| 662 CheckedNumeric<Promotion>::cast(rhs); \ |
| 663 } \ |
| 664 /* Assignment arithmetic operator implementation from CheckedNumeric above. */ \ |
| 665 template <typename T> \ |
| 666 template <typename Src> \ |
| 667 CheckedNumeric<T>& \ |
| 668 CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ |
| 669 *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \ |
| 670 return *this; \ |
| 671 } \ |
| 672 /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ |
| 673 template <typename T, typename Src> \ |
| 674 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \ |
| 675 operator OP(Src lhs, const CheckedNumeric<T> &rhs) { \ |
| 676 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \ |
| 677 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ |
| 678 return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ |
| 679 rhs.validity()); \ |
| 680 return CheckedNumeric<Promotion>::cast(lhs) OP \ |
| 681 CheckedNumeric<Promotion>::cast(rhs); \ |
| 682 } |
| 683 |
| 684 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) |
| 685 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) |
| 686 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) |
| 687 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) |
| 688 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) |
| 689 |
| 690 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS |
| 691 |
| 692 } // namespace internal |
| 693 } // namespace base |
| 694 |
| 695 #endif // SAFE_MATH_IMPL_H_ |
| 696 |
OLD | NEW |