| OLD | NEW |
| (Empty) |
| 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, | |
| 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 5 | |
| 6 /* Provides checked integers, detecting integer overflow and divide-by-0. */ | |
| 7 | |
| 8 // Necessary modifications are made to the original CheckedInt.h file when | |
| 9 // incorporating it into WebKit: | |
| 10 // 1) Comment out #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS | |
| 11 // 2) Comment out #include "mozilla/StandardInteger.h" | |
| 12 // 3) Define MOZ_DELETE | |
| 13 // 4) Change namespace mozilla to namespace WebCore | |
| 14 | |
| 15 #ifndef mozilla_CheckedInt_h_ | |
| 16 #define mozilla_CheckedInt_h_ | |
| 17 | |
| 18 /* | |
| 19 * Build options. Comment out these #defines to disable the corresponding | |
| 20 * optional feature. Disabling features may be useful for code using | |
| 21 * CheckedInt outside of Mozilla (e.g. WebKit) | |
| 22 */ | |
| 23 | |
| 24 // Enable usage of MOZ_STATIC_ASSERT to check for unsupported types. | |
| 25 // If disabled, static asserts are replaced by regular assert(). | |
| 26 // #define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS | |
| 27 | |
| 28 /* | |
| 29 * End of build options | |
| 30 */ | |
| 31 | |
| 32 #ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS | |
| 33 # include "mozilla/Assertions.h" | |
| 34 #else | |
| 35 # ifndef MOZ_STATIC_ASSERT | |
| 36 # include <cassert> | |
| 37 # define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason) | |
| 38 # define MOZ_ASSERT(cond, reason) assert((cond) && reason) | |
| 39 # endif | |
| 40 #endif | |
| 41 | |
| 42 // #include "mozilla/StandardInteger.h" | |
| 43 | |
| 44 #ifndef MOZ_DELETE | |
| 45 #define MOZ_DELETE | |
| 46 #endif | |
| 47 | |
| 48 #include <climits> | |
| 49 #include <cstddef> | |
| 50 | |
| 51 namespace WebCore { | |
| 52 | |
| 53 namespace detail { | |
| 54 | |
| 55 /* | |
| 56 * Step 1: manually record supported types | |
| 57 * | |
| 58 * What's nontrivial here is that there are different families of integer | |
| 59 * types: basic integer types and stdint types. It is merrily undefined which | |
| 60 * types from one family may be just typedefs for a type from another family. | |
| 61 * | |
| 62 * For example, on GCC 4.6, aside from the basic integer types, the only other | |
| 63 * type that isn't just a typedef for some of them, is int8_t. | |
| 64 */ | |
| 65 | |
| 66 struct UnsupportedType {}; | |
| 67 | |
| 68 template<typename IntegerType> | |
| 69 struct IsSupportedPass2 | |
| 70 { | |
| 71 static const bool value = false; | |
| 72 }; | |
| 73 | |
| 74 template<typename IntegerType> | |
| 75 struct IsSupported | |
| 76 { | |
| 77 static const bool value = IsSupportedPass2<IntegerType>::value; | |
| 78 }; | |
| 79 | |
| 80 template<> | |
| 81 struct IsSupported<int8_t> | |
| 82 { static const bool value = true; }; | |
| 83 | |
| 84 template<> | |
| 85 struct IsSupported<uint8_t> | |
| 86 { static const bool value = true; }; | |
| 87 | |
| 88 template<> | |
| 89 struct IsSupported<int16_t> | |
| 90 { static const bool value = true; }; | |
| 91 | |
| 92 template<> | |
| 93 struct IsSupported<uint16_t> | |
| 94 { static const bool value = true; }; | |
| 95 | |
| 96 template<> | |
| 97 struct IsSupported<int32_t> | |
| 98 { static const bool value = true; }; | |
| 99 | |
| 100 template<> | |
| 101 struct IsSupported<uint32_t> | |
| 102 { static const bool value = true; }; | |
| 103 | |
| 104 template<> | |
| 105 struct IsSupported<int64_t> | |
| 106 { static const bool value = true; }; | |
| 107 | |
| 108 template<> | |
| 109 struct IsSupported<uint64_t> | |
| 110 { static const bool value = true; }; | |
| 111 | |
| 112 | |
| 113 template<> | |
| 114 struct IsSupportedPass2<char> | |
| 115 { static const bool value = true; }; | |
| 116 | |
| 117 template<> | |
| 118 struct IsSupportedPass2<unsigned char> | |
| 119 { static const bool value = true; }; | |
| 120 | |
| 121 template<> | |
| 122 struct IsSupportedPass2<short> | |
| 123 { static const bool value = true; }; | |
| 124 | |
| 125 template<> | |
| 126 struct IsSupportedPass2<unsigned short> | |
| 127 { static const bool value = true; }; | |
| 128 | |
| 129 template<> | |
| 130 struct IsSupportedPass2<int> | |
| 131 { static const bool value = true; }; | |
| 132 | |
| 133 template<> | |
| 134 struct IsSupportedPass2<unsigned int> | |
| 135 { static const bool value = true; }; | |
| 136 | |
| 137 template<> | |
| 138 struct IsSupportedPass2<long> | |
| 139 { static const bool value = true; }; | |
| 140 | |
| 141 template<> | |
| 142 struct IsSupportedPass2<unsigned long> | |
| 143 { static const bool value = true; }; | |
| 144 | |
| 145 | |
| 146 /* | |
| 147 * Step 2: some integer-traits kind of stuff. | |
| 148 */ | |
| 149 | |
| 150 template<size_t Size, bool Signedness> | |
| 151 struct StdintTypeForSizeAndSignedness | |
| 152 {}; | |
| 153 | |
| 154 template<> | |
| 155 struct StdintTypeForSizeAndSignedness<1, true> | |
| 156 { typedef int8_t Type; }; | |
| 157 | |
| 158 template<> | |
| 159 struct StdintTypeForSizeAndSignedness<1, false> | |
| 160 { typedef uint8_t Type; }; | |
| 161 | |
| 162 template<> | |
| 163 struct StdintTypeForSizeAndSignedness<2, true> | |
| 164 { typedef int16_t Type; }; | |
| 165 | |
| 166 template<> | |
| 167 struct StdintTypeForSizeAndSignedness<2, false> | |
| 168 { typedef uint16_t Type; }; | |
| 169 | |
| 170 template<> | |
| 171 struct StdintTypeForSizeAndSignedness<4, true> | |
| 172 { typedef int32_t Type; }; | |
| 173 | |
| 174 template<> | |
| 175 struct StdintTypeForSizeAndSignedness<4, false> | |
| 176 { typedef uint32_t Type; }; | |
| 177 | |
| 178 template<> | |
| 179 struct StdintTypeForSizeAndSignedness<8, true> | |
| 180 { typedef int64_t Type; }; | |
| 181 | |
| 182 template<> | |
| 183 struct StdintTypeForSizeAndSignedness<8, false> | |
| 184 { typedef uint64_t Type; }; | |
| 185 | |
| 186 template<typename IntegerType> | |
| 187 struct UnsignedType | |
| 188 { | |
| 189 typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType), | |
| 190 false>::Type Type; | |
| 191 }; | |
| 192 | |
| 193 template<typename IntegerType> | |
| 194 struct IsSigned | |
| 195 { | |
| 196 static const bool value = IntegerType(-1) <= IntegerType(0); | |
| 197 }; | |
| 198 | |
| 199 template<typename IntegerType, size_t Size = sizeof(IntegerType)> | |
| 200 struct TwiceBiggerType | |
| 201 { | |
| 202 typedef typename StdintTypeForSizeAndSignedness< | |
| 203 sizeof(IntegerType) * 2, | |
| 204 IsSigned<IntegerType>::value | |
| 205 >::Type Type; | |
| 206 }; | |
| 207 | |
| 208 template<typename IntegerType> | |
| 209 struct TwiceBiggerType<IntegerType, 8> | |
| 210 { | |
| 211 typedef UnsupportedType Type; | |
| 212 }; | |
| 213 | |
| 214 template<typename IntegerType> | |
| 215 struct PositionOfSignBit | |
| 216 { | |
| 217 static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1; | |
| 218 }; | |
| 219 | |
| 220 template<typename IntegerType> | |
| 221 struct MinValue | |
| 222 { | |
| 223 private: | |
| 224 typedef typename UnsignedType<IntegerType>::Type UnsignedIntegerType; | |
| 225 static const size_t PosOfSignBit = PositionOfSignBit<IntegerType>::value; | |
| 226 | |
| 227 public: | |
| 228 // Bitwise ops may return a larger type, that's why we cast explicitly. | |
| 229 // In C++, left bit shifts on signed values is undefined by the standard | |
| 230 // unless the shifted value is representable. | |
| 231 // Notice that signed-to-unsigned conversions are always well-defined in | |
| 232 // the standard as the value congruent to 2**n, as expected. By contrast, | |
| 233 // unsigned-to-signed is only well-defined if the value is representable. | |
| 234 static const IntegerType value = | |
| 235 IsSigned<IntegerType>::value | |
| 236 ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) | |
| 237 : IntegerType(0); | |
| 238 }; | |
| 239 | |
| 240 template<typename IntegerType> | |
| 241 struct MaxValue | |
| 242 { | |
| 243 // Tricksy, but covered by the unit test. | |
| 244 // Relies heavily on the type of MinValue<IntegerType>::value | |
| 245 // being IntegerType. | |
| 246 static const IntegerType value = ~MinValue<IntegerType>::value; | |
| 247 }; | |
| 248 | |
| 249 /* | |
| 250 * Step 3: Implement the actual validity checks. | |
| 251 * | |
| 252 * Ideas taken from IntegerLib, code different. | |
| 253 */ | |
| 254 | |
| 255 template<typename T> | |
| 256 inline bool | |
| 257 HasSignBit(T x) | |
| 258 { | |
| 259 // In C++, right bit shifts on negative values is undefined by the standard. | |
| 260 // Notice that signed-to-unsigned conversions are always well-defined in the | |
| 261 // standard, as the value congruent modulo 2**n as expected. By contrast, | |
| 262 // unsigned-to-signed is only well-defined if the value is representable. | |
| 263 return bool(typename UnsignedType<T>::Type(x) | |
| 264 >> PositionOfSignBit<T>::value); | |
| 265 } | |
| 266 | |
| 267 // Bitwise ops may return a larger type, so it's good to use this inline | |
| 268 // helper guaranteeing that the result is really of type T. | |
| 269 template<typename T> | |
| 270 inline T | |
| 271 BinaryComplement(T x) | |
| 272 { | |
| 273 return ~x; | |
| 274 } | |
| 275 | |
| 276 template<typename T, | |
| 277 typename U, | |
| 278 bool IsTSigned = IsSigned<T>::value, | |
| 279 bool IsUSigned = IsSigned<U>::value> | |
| 280 struct DoesRangeContainRange | |
| 281 { | |
| 282 }; | |
| 283 | |
| 284 template<typename T, typename U, bool Signedness> | |
| 285 struct DoesRangeContainRange<T, U, Signedness, Signedness> | |
| 286 { | |
| 287 static const bool value = sizeof(T) >= sizeof(U); | |
| 288 }; | |
| 289 | |
| 290 template<typename T, typename U> | |
| 291 struct DoesRangeContainRange<T, U, true, false> | |
| 292 { | |
| 293 static const bool value = sizeof(T) > sizeof(U); | |
| 294 }; | |
| 295 | |
| 296 template<typename T, typename U> | |
| 297 struct DoesRangeContainRange<T, U, false, true> | |
| 298 { | |
| 299 static const bool value = false; | |
| 300 }; | |
| 301 | |
| 302 template<typename T, | |
| 303 typename U, | |
| 304 bool IsTSigned = IsSigned<T>::value, | |
| 305 bool IsUSigned = IsSigned<U>::value, | |
| 306 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value> | |
| 307 struct IsInRangeImpl {}; | |
| 308 | |
| 309 template<typename T, typename U, bool IsTSigned, bool IsUSigned> | |
| 310 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true> | |
| 311 { | |
| 312 static bool run(U) | |
| 313 { | |
| 314 return true; | |
| 315 } | |
| 316 }; | |
| 317 | |
| 318 template<typename T, typename U> | |
| 319 struct IsInRangeImpl<T, U, true, true, false> | |
| 320 { | |
| 321 static bool run(U x) | |
| 322 { | |
| 323 return x <= MaxValue<T>::value && x >= MinValue<T>::value; | |
| 324 } | |
| 325 }; | |
| 326 | |
| 327 template<typename T, typename U> | |
| 328 struct IsInRangeImpl<T, U, false, false, false> | |
| 329 { | |
| 330 static bool run(U x) | |
| 331 { | |
| 332 return x <= MaxValue<T>::value; | |
| 333 } | |
| 334 }; | |
| 335 | |
| 336 template<typename T, typename U> | |
| 337 struct IsInRangeImpl<T, U, true, false, false> | |
| 338 { | |
| 339 static bool run(U x) | |
| 340 { | |
| 341 return sizeof(T) > sizeof(U) || x <= U(MaxValue<T>::value); | |
| 342 } | |
| 343 }; | |
| 344 | |
| 345 template<typename T, typename U> | |
| 346 struct IsInRangeImpl<T, U, false, true, false> | |
| 347 { | |
| 348 static bool run(U x) | |
| 349 { | |
| 350 return sizeof(T) >= sizeof(U) | |
| 351 ? x >= 0 | |
| 352 : x >= 0 && x <= U(MaxValue<T>::value); | |
| 353 } | |
| 354 }; | |
| 355 | |
| 356 template<typename T, typename U> | |
| 357 inline bool | |
| 358 IsInRange(U x) | |
| 359 { | |
| 360 return IsInRangeImpl<T, U>::run(x); | |
| 361 } | |
| 362 | |
| 363 template<typename T> | |
| 364 inline bool | |
| 365 IsAddValid(T x, T y) | |
| 366 { | |
| 367 // Addition is valid if the sign of x+y is equal to either that of x or that | |
| 368 // of y. Since the value of x+y is undefined if we have a signed type, we | |
| 369 // compute it using the unsigned type of the same size. | |
| 370 // Beware! These bitwise operations can return a larger integer type, | |
| 371 // if T was a small type like int8_t, so we explicitly cast to T. | |
| 372 | |
| 373 typename UnsignedType<T>::Type ux = x; | |
| 374 typename UnsignedType<T>::Type uy = y; | |
| 375 typename UnsignedType<T>::Type result = ux + uy; | |
| 376 return IsSigned<T>::value | |
| 377 ? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y)))) | |
| 378 : BinaryComplement(x) >= y; | |
| 379 } | |
| 380 | |
| 381 template<typename T> | |
| 382 inline bool | |
| 383 IsSubValid(T x, T y) | |
| 384 { | |
| 385 // Subtraction is valid if either x and y have same sign, or x-y and x have | |
| 386 // same sign. Since the value of x-y is undefined if we have a signed type, | |
| 387 // we compute it using the unsigned type of the same size. | |
| 388 typename UnsignedType<T>::Type ux = x; | |
| 389 typename UnsignedType<T>::Type uy = y; | |
| 390 typename UnsignedType<T>::Type result = ux - uy; | |
| 391 | |
| 392 return IsSigned<T>::value | |
| 393 ? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y)))) | |
| 394 : x >= y; | |
| 395 } | |
| 396 | |
| 397 template<typename T, | |
| 398 bool IsSigned = IsSigned<T>::value, | |
| 399 bool TwiceBiggerTypeIsSupported = | |
| 400 IsSupported<typename TwiceBiggerType<T>::Type>::value> | |
| 401 struct IsMulValidImpl {}; | |
| 402 | |
| 403 template<typename T, bool IsSigned> | |
| 404 struct IsMulValidImpl<T, IsSigned, true> | |
| 405 { | |
| 406 static bool run(T x, T y) | |
| 407 { | |
| 408 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType; | |
| 409 TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y); | |
| 410 return IsInRange<T>(product); | |
| 411 } | |
| 412 }; | |
| 413 | |
| 414 template<typename T> | |
| 415 struct IsMulValidImpl<T, true, false> | |
| 416 { | |
| 417 static bool run(T x, T y) | |
| 418 { | |
| 419 const T max = MaxValue<T>::value; | |
| 420 const T min = MinValue<T>::value; | |
| 421 | |
| 422 if (x == 0 || y == 0) | |
| 423 return true; | |
| 424 | |
| 425 if (x > 0) { | |
| 426 return y > 0 | |
| 427 ? x <= max / y | |
| 428 : y >= min / x; | |
| 429 } | |
| 430 | |
| 431 // If we reach this point, we know that x < 0. | |
| 432 return y > 0 | |
| 433 ? x >= min / y | |
| 434 : y >= max / x; | |
| 435 } | |
| 436 }; | |
| 437 | |
| 438 template<typename T> | |
| 439 struct IsMulValidImpl<T, false, false> | |
| 440 { | |
| 441 static bool run(T x, T y) | |
| 442 { | |
| 443 return y == 0 || x <= MaxValue<T>::value / y; | |
| 444 } | |
| 445 }; | |
| 446 | |
| 447 template<typename T> | |
| 448 inline bool | |
| 449 IsMulValid(T x, T y) | |
| 450 { | |
| 451 return IsMulValidImpl<T>::run(x, y); | |
| 452 } | |
| 453 | |
| 454 template<typename T> | |
| 455 inline bool | |
| 456 IsDivValid(T x, T y) | |
| 457 { | |
| 458 // Keep in mind that in the signed case, min/-1 is invalid because abs(min)>ma
x. | |
| 459 return y != 0 && | |
| 460 !(IsSigned<T>::value && x == MinValue<T>::value && y == T(-1)); | |
| 461 } | |
| 462 | |
| 463 // This is just to shut up msvc warnings about negating unsigned ints. | |
| 464 template<typename T, bool IsSigned = IsSigned<T>::value> | |
| 465 struct OppositeIfSignedImpl | |
| 466 { | |
| 467 static T run(T x) { return -x; } | |
| 468 }; | |
| 469 template<typename T> | |
| 470 struct OppositeIfSignedImpl<T, false> | |
| 471 { | |
| 472 static T run(T x) { return x; } | |
| 473 }; | |
| 474 template<typename T> | |
| 475 inline T | |
| 476 OppositeIfSigned(T x) | |
| 477 { | |
| 478 return OppositeIfSignedImpl<T>::run(x); | |
| 479 } | |
| 480 | |
| 481 } // namespace detail | |
| 482 | |
| 483 | |
| 484 /* | |
| 485 * Step 4: Now define the CheckedInt class. | |
| 486 */ | |
| 487 | |
| 488 /** | |
| 489 * @class CheckedInt | |
| 490 * @brief Integer wrapper class checking for integer overflow and other errors | |
| 491 * @param T the integer type to wrap. Can be any type among the following: | |
| 492 * - any basic integer type such as |int| | |
| 493 * - any stdint type such as |int8_t| | |
| 494 * | |
| 495 * This class implements guarded integer arithmetic. Do a computation, check | |
| 496 * that isValid() returns true, you then have a guarantee that no problem, such | |
| 497 * as integer overflow, happened during this computation, and you can call | |
| 498 * value() to get the plain integer value. | |
| 499 * | |
| 500 * The arithmetic operators in this class are guaranteed not to raise a signal | |
| 501 * (e.g. in case of a division by zero). | |
| 502 * | |
| 503 * For example, suppose that you want to implement a function that computes | |
| 504 * (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by | |
| 505 * zero or integer overflow). You could code it as follows: | |
| 506 @code | |
| 507 bool computeXPlusYOverZ(int x, int y, int z, int *result) | |
| 508 { | |
| 509 CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z; | |
| 510 if (checkedResult.isValid()) { | |
| 511 *result = checkedResult.value(); | |
| 512 return true; | |
| 513 } else { | |
| 514 return false; | |
| 515 } | |
| 516 } | |
| 517 @endcode | |
| 518 * | |
| 519 * Implicit conversion from plain integers to checked integers is allowed. The | |
| 520 * plain integer is checked to be in range before being casted to the | |
| 521 * destination type. This means that the following lines all compile, and the | |
| 522 * resulting CheckedInts are correctly detected as valid or invalid: | |
| 523 * @code | |
| 524 // 1 is of type int, is found to be in range for uint8_t, x is valid | |
| 525 CheckedInt<uint8_t> x(1); | |
| 526 // -1 is of type int, is found not to be in range for uint8_t, x is invalid | |
| 527 CheckedInt<uint8_t> x(-1); | |
| 528 // -1 is of type int, is found to be in range for int8_t, x is valid | |
| 529 CheckedInt<int8_t> x(-1); | |
| 530 // 1000 is of type int16_t, is found not to be in range for int8_t, | |
| 531 // x is invalid | |
| 532 CheckedInt<int8_t> x(int16_t(1000)); | |
| 533 // 3123456789 is of type uint32_t, is found not to be in range for int32_t, | |
| 534 // x is invalid | |
| 535 CheckedInt<int32_t> x(uint32_t(3123456789)); | |
| 536 * @endcode | |
| 537 * Implicit conversion from | |
| 538 * checked integers to plain integers is not allowed. As shown in the | |
| 539 * above example, to get the value of a checked integer as a normal integer, | |
| 540 * call value(). | |
| 541 * | |
| 542 * Arithmetic operations between checked and plain integers is allowed; the | |
| 543 * result type is the type of the checked integer. | |
| 544 * | |
| 545 * Checked integers of different types cannot be used in the same arithmetic | |
| 546 * expression. | |
| 547 * | |
| 548 * There are convenience typedefs for all stdint types, of the following form | |
| 549 * (these are just 2 examples): | |
| 550 @code | |
| 551 typedef CheckedInt<int32_t> CheckedInt32; | |
| 552 typedef CheckedInt<uint16_t> CheckedUint16; | |
| 553 @endcode | |
| 554 */ | |
| 555 template<typename T> | |
| 556 class CheckedInt | |
| 557 { | |
| 558 protected: | |
| 559 T mValue; | |
| 560 bool mIsValid; | |
| 561 | |
| 562 template<typename U> | |
| 563 CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid) | |
| 564 { | |
| 565 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, | |
| 566 "This type is not supported by CheckedInt"); | |
| 567 } | |
| 568 | |
| 569 public: | |
| 570 /** | |
| 571 * Constructs a checked integer with given @a value. The checked integer is | |
| 572 * initialized as valid or invalid depending on whether the @a value | |
| 573 * is in range. | |
| 574 * | |
| 575 * This constructor is not explicit. Instead, the type of its argument is a | |
| 576 * separate template parameter, ensuring that no conversion is performed | |
| 577 * before this constructor is actually called. As explained in the above | |
| 578 * documentation for class CheckedInt, this constructor checks that its | |
| 579 * argument is valid. | |
| 580 */ | |
| 581 template<typename U> | |
| 582 CheckedInt(U value) | |
| 583 : mValue(T(value)), | |
| 584 mIsValid(detail::IsInRange<T>(value)) | |
| 585 { | |
| 586 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, | |
| 587 "This type is not supported by CheckedInt"); | |
| 588 } | |
| 589 | |
| 590 /** Constructs a valid checked integer with initial value 0 */ | |
| 591 CheckedInt() : mValue(0), mIsValid(true) | |
| 592 { | |
| 593 MOZ_STATIC_ASSERT(detail::IsSupported<T>::value, | |
| 594 "This type is not supported by CheckedInt"); | |
| 595 } | |
| 596 | |
| 597 /** @returns the actual value */ | |
| 598 T value() const | |
| 599 { | |
| 600 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer
overflow)"); | |
| 601 return mValue; | |
| 602 } | |
| 603 | |
| 604 /** | |
| 605 * @returns true if the checked integer is valid, i.e. is not the result | |
| 606 * of an invalid operation or of an operation involving an invalid checked | |
| 607 * integer | |
| 608 */ | |
| 609 bool isValid() const | |
| 610 { | |
| 611 return mIsValid; | |
| 612 } | |
| 613 | |
| 614 template<typename U> | |
| 615 friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, | |
| 616 const CheckedInt<U>& rhs); | |
| 617 template<typename U> | |
| 618 CheckedInt& operator +=(U rhs); | |
| 619 template<typename U> | |
| 620 friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, | |
| 621 const CheckedInt<U> &rhs); | |
| 622 template<typename U> | |
| 623 CheckedInt& operator -=(U rhs); | |
| 624 template<typename U> | |
| 625 friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, | |
| 626 const CheckedInt<U> &rhs); | |
| 627 template<typename U> | |
| 628 CheckedInt& operator *=(U rhs); | |
| 629 template<typename U> | |
| 630 friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, | |
| 631 const CheckedInt<U> &rhs); | |
| 632 template<typename U> | |
| 633 CheckedInt& operator /=(U rhs); | |
| 634 | |
| 635 CheckedInt operator -() const | |
| 636 { | |
| 637 // Circumvent msvc warning about - applied to unsigned int. | |
| 638 // if we're unsigned, the only valid case anyway is 0 | |
| 639 // in which case - is a no-op. | |
| 640 T result = detail::OppositeIfSigned(mValue); | |
| 641 /* Help the compiler perform RVO (return value optimization). */ | |
| 642 return CheckedInt(result, | |
| 643 mIsValid && detail::IsSubValid(T(0), | |
| 644 mValue)); | |
| 645 } | |
| 646 | |
| 647 /** | |
| 648 * @returns true if the left and right hand sides are valid | |
| 649 * and have the same value. | |
| 650 * | |
| 651 * Note that these semantics are the reason why we don't offer | |
| 652 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b) | |
| 653 * but that would mean that whenever a or b is invalid, a!=b | |
| 654 * is always true, which would be very confusing. | |
| 655 * | |
| 656 * For similar reasons, operators <, >, <=, >= would be very tricky to | |
| 657 * specify, so we just avoid offering them. | |
| 658 * | |
| 659 * Notice that these == semantics are made more reasonable by these facts: | |
| 660 * 1. a==b implies equality at the raw data level | |
| 661 * (the converse is false, as a==b is never true among invalids) | |
| 662 * 2. This is similar to the behavior of IEEE floats, where a==b | |
| 663 * means that a and b have the same value *and* neither is NaN. | |
| 664 */ | |
| 665 bool operator ==(const CheckedInt& other) const | |
| 666 { | |
| 667 return mIsValid && other.mIsValid && mValue == other.mValue; | |
| 668 } | |
| 669 | |
| 670 /** prefix ++ */ | |
| 671 CheckedInt& operator++() | |
| 672 { | |
| 673 *this += 1; | |
| 674 return *this; | |
| 675 } | |
| 676 | |
| 677 /** postfix ++ */ | |
| 678 CheckedInt operator++(int) | |
| 679 { | |
| 680 CheckedInt tmp = *this; | |
| 681 *this += 1; | |
| 682 return tmp; | |
| 683 } | |
| 684 | |
| 685 /** prefix -- */ | |
| 686 CheckedInt& operator--() | |
| 687 { | |
| 688 *this -= 1; | |
| 689 return *this; | |
| 690 } | |
| 691 | |
| 692 /** postfix -- */ | |
| 693 CheckedInt operator--(int) | |
| 694 { | |
| 695 CheckedInt tmp = *this; | |
| 696 *this -= 1; | |
| 697 return tmp; | |
| 698 } | |
| 699 | |
| 700 private: | |
| 701 /** | |
| 702 * The !=, <, <=, >, >= operators are disabled: | |
| 703 * see the comment on operator==. | |
| 704 */ | |
| 705 template<typename U> | |
| 706 bool operator !=(U other) const MOZ_DELETE; | |
| 707 template<typename U> | |
| 708 bool operator <(U other) const MOZ_DELETE; | |
| 709 template<typename U> | |
| 710 bool operator <=(U other) const MOZ_DELETE; | |
| 711 template<typename U> | |
| 712 bool operator >(U other) const MOZ_DELETE; | |
| 713 template<typename U> | |
| 714 bool operator >=(U other) const MOZ_DELETE; | |
| 715 }; | |
| 716 | |
| 717 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ | |
| 718 template<typename T> \ | |
| 719 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \ | |
| 720 const CheckedInt<T> &rhs) \ | |
| 721 { \ | |
| 722 if (!detail::Is##NAME##Valid(lhs.mValue, rhs.mValue)) \ | |
| 723 return CheckedInt<T>(0, false); \ | |
| 724 \ | |
| 725 return CheckedInt<T>(lhs.mValue OP rhs.mValue, \ | |
| 726 lhs.mIsValid && rhs.mIsValid); \ | |
| 727 } | |
| 728 | |
| 729 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) | |
| 730 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) | |
| 731 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) | |
| 732 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) | |
| 733 | |
| 734 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR | |
| 735 | |
| 736 // Implement castToCheckedInt<T>(x), making sure that | |
| 737 // - it allows x to be either a CheckedInt<T> or any integer type | |
| 738 // that can be casted to T | |
| 739 // - if x is already a CheckedInt<T>, we just return a reference to it, | |
| 740 // instead of copying it (optimization) | |
| 741 | |
| 742 namespace detail { | |
| 743 | |
| 744 template<typename T, typename U> | |
| 745 struct CastToCheckedIntImpl | |
| 746 { | |
| 747 typedef CheckedInt<T> ReturnType; | |
| 748 static CheckedInt<T> run(U u) { return u; } | |
| 749 }; | |
| 750 | |
| 751 template<typename T> | |
| 752 struct CastToCheckedIntImpl<T, CheckedInt<T> > | |
| 753 { | |
| 754 typedef const CheckedInt<T>& ReturnType; | |
| 755 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; } | |
| 756 }; | |
| 757 | |
| 758 } // namespace detail | |
| 759 | |
| 760 template<typename T, typename U> | |
| 761 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType | |
| 762 castToCheckedInt(U u) | |
| 763 { | |
| 764 return detail::CastToCheckedIntImpl<T, U>::run(u); | |
| 765 } | |
| 766 | |
| 767 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ | |
| 768 template<typename T> \ | |
| 769 template<typename U> \ | |
| 770 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \ | |
| 771 { \ | |
| 772 *this = *this OP castToCheckedInt<T>(rhs); \ | |
| 773 return *this; \ | |
| 774 } \ | |
| 775 template<typename T, typename U> \ | |
| 776 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \ | |
| 777 { \ | |
| 778 return lhs OP castToCheckedInt<T>(rhs); \ | |
| 779 } \ | |
| 780 template<typename T, typename U> \ | |
| 781 inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \ | |
| 782 { \ | |
| 783 return castToCheckedInt<T>(lhs) OP rhs; \ | |
| 784 } | |
| 785 | |
| 786 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) | |
| 787 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=) | |
| 788 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=) | |
| 789 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=) | |
| 790 | |
| 791 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS | |
| 792 | |
| 793 template<typename T, typename U> | |
| 794 inline bool | |
| 795 operator ==(const CheckedInt<T> &lhs, U rhs) | |
| 796 { | |
| 797 return lhs == castToCheckedInt<T>(rhs); | |
| 798 } | |
| 799 | |
| 800 template<typename T, typename U> | |
| 801 inline bool | |
| 802 operator ==(U lhs, const CheckedInt<T> &rhs) | |
| 803 { | |
| 804 return castToCheckedInt<T>(lhs) == rhs; | |
| 805 } | |
| 806 | |
| 807 // Convenience typedefs. | |
| 808 typedef CheckedInt<int8_t> CheckedInt8; | |
| 809 typedef CheckedInt<uint8_t> CheckedUint8; | |
| 810 typedef CheckedInt<int16_t> CheckedInt16; | |
| 811 typedef CheckedInt<uint16_t> CheckedUint16; | |
| 812 typedef CheckedInt<int32_t> CheckedInt32; | |
| 813 typedef CheckedInt<uint32_t> CheckedUint32; | |
| 814 typedef CheckedInt<int64_t> CheckedInt64; | |
| 815 typedef CheckedInt<uint64_t> CheckedUint64; | |
| 816 | |
| 817 } // namespace WebCore | |
| 818 | |
| 819 #endif /* mozilla_CheckedInt_h_ */ | |
| OLD | NEW |