| 1 | /* | 
| 2 |  * Copyright (C) 2011 Apple Inc. All rights reserved. | 
| 3 |  * | 
| 4 |  * Redistribution and use in source and binary forms, with or without | 
| 5 |  * modification, are permitted provided that the following conditions | 
| 6 |  * are met: | 
| 7 |  * 1. Redistributions of source code must retain the above copyright | 
| 8 |  *    notice, this list of conditions and the following disclaimer. | 
| 9 |  * 2. Redistributions in binary form must reproduce the above copyright | 
| 10 |  *    notice, this list of conditions and the following disclaimer in the | 
| 11 |  *    documentation and/or other materials provided with the distribution. | 
| 12 |  * | 
| 13 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
| 14 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
| 15 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
| 16 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
| 17 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
| 18 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
| 19 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
| 20 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
| 21 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 22 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 23 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
| 24 |  */ | 
| 25 |  | 
| 26 | #ifndef CheckedArithmetic_h | 
| 27 | #define CheckedArithmetic_h | 
| 28 |  | 
| 29 | #include <wtf/Assertions.h> | 
| 30 | #include <wtf/EnumClass.h> | 
| 31 | #include <wtf/TypeTraits.h> | 
| 32 |  | 
| 33 | #include <limits> | 
| 34 | #include <stdint.h> | 
| 35 |  | 
| 36 | /* Checked<T> | 
| 37 |  * | 
| 38 |  * This class provides a mechanism to perform overflow-safe integer arithmetic | 
| 39 |  * without having to manually ensure that you have all the required bounds checks | 
| 40 |  * directly in your code. | 
| 41 |  * | 
| 42 |  * There are two modes of operation: | 
| 43 |  *  - The default is Checked<T, CrashOnOverflow>, and crashes at the point | 
| 44 |  *    and overflow has occurred. | 
| 45 |  *  - The alternative is Checked<T, RecordOverflow>, which uses an additional | 
| 46 |  *    byte of storage to track whether an overflow has occurred, subsequent | 
| 47 |  *    unchecked operations will crash if an overflow has occured | 
| 48 |  * | 
| 49 |  * It is possible to provide a custom overflow handler, in which case you need | 
| 50 |  * to support these functions: | 
| 51 |  *  - void overflowed(); | 
| 52 |  *    This function is called when an operation has produced an overflow. | 
| 53 |  *  - bool hasOverflowed(); | 
| 54 |  *    This function must return true if overflowed() has been called on an | 
| 55 |  *    instance and false if it has not. | 
| 56 |  *  - void clearOverflow(); | 
| 57 |  *    Used to reset overflow tracking when a value is being overwritten with | 
| 58 |  *    a new value. | 
| 59 |  * | 
| 60 |  * Checked<T> works for all integer types, with the following caveats: | 
| 61 |  *  - Mixing signedness of operands is only supported for types narrower than | 
| 62 |  *    64bits. | 
| 63 |  *  - It does have a performance impact, so tight loops may want to be careful | 
| 64 |  *    when using it. | 
| 65 |  * | 
| 66 |  */ | 
| 67 |  | 
| 68 | namespace WTF { | 
| 69 |  | 
| 70 | ENUM_CLASS(CheckedState) | 
| 71 | { | 
| 72 |     DidOverflow, | 
| 73 |     DidNotOverflow | 
| 74 | } ENUM_CLASS_END(CheckedState); | 
| 75 |      | 
| 76 | class CrashOnOverflow { | 
| 77 | public: | 
| 78 |     static NO_RETURN_DUE_TO_CRASH void overflowed() | 
| 79 |     { | 
| 80 |         CRASH(); | 
| 81 |     } | 
| 82 |  | 
| 83 |     void clearOverflow() { } | 
| 84 |  | 
| 85 | public: | 
| 86 |     bool hasOverflowed() const { return false; } | 
| 87 | }; | 
| 88 |  | 
| 89 | class RecordOverflow { | 
| 90 | protected: | 
| 91 |     RecordOverflow() | 
| 92 |         : m_overflowed(false) | 
| 93 |     { | 
| 94 |     } | 
| 95 |  | 
| 96 |     void overflowed() | 
| 97 |     { | 
| 98 |         m_overflowed = true; | 
| 99 |     } | 
| 100 |  | 
| 101 |     void clearOverflow() | 
| 102 |     { | 
| 103 |         m_overflowed = false; | 
| 104 |     } | 
| 105 |  | 
| 106 | public: | 
| 107 |     bool hasOverflowed() const { return m_overflowed; } | 
| 108 |  | 
| 109 | private: | 
| 110 |     unsigned char m_overflowed; | 
| 111 | }; | 
| 112 |  | 
| 113 | template <typename T, class OverflowHandler = CrashOnOverflow> class Checked; | 
| 114 | template <typename T> struct RemoveChecked; | 
| 115 | template <typename T> struct RemoveChecked<Checked<T> >; | 
| 116 |  | 
| 117 | template <typename Target, typename Source, bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker; | 
| 118 | template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> { | 
| 119 |     static bool inBounds(Source value) | 
| 120 |     { | 
| 121 |         // Same signedness so implicit type conversion will always increase precision | 
| 122 |         // to widest type | 
| 123 |         return value <= std::numeric_limits<Target>::max(); | 
| 124 |     } | 
| 125 | }; | 
| 126 |  | 
| 127 | template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> { | 
| 128 |     static bool inBounds(Source value) | 
| 129 |     { | 
| 130 |         // Same signedness so implicit type conversion will always increase precision | 
| 131 |         // to widest type | 
| 132 |         return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max(); | 
| 133 |     } | 
| 134 | }; | 
| 135 |  | 
| 136 | template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> { | 
| 137 |     static bool inBounds(Source value) | 
| 138 |     { | 
| 139 |         // Target is unsigned so any value less than zero is clearly unsafe | 
| 140 |         if (value < 0) | 
| 141 |             return false; | 
| 142 |         // If our (unsigned) Target is the same or greater width we can | 
| 143 |         // convert value to type Target without losing precision | 
| 144 |         if (sizeof(Target) >= sizeof(Source))  | 
| 145 |             return static_cast<Target>(value) <= std::numeric_limits<Target>::max(); | 
| 146 |         // The signed Source type has greater precision than the target so | 
| 147 |         // max(Target) -> Source will widen. | 
| 148 |         return value <= static_cast<Source>(std::numeric_limits<Target>::max()); | 
| 149 |     } | 
| 150 | }; | 
| 151 |  | 
| 152 | template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> { | 
| 153 |     static bool inBounds(Source value) | 
| 154 |     { | 
| 155 |         // Signed target with an unsigned source | 
| 156 |         if (sizeof(Target) <= sizeof(Source))  | 
| 157 |             return value <= static_cast<Source>(std::numeric_limits<Target>::max()); | 
| 158 |         // Target is Wider than Source so we're guaranteed to fit any value in | 
| 159 |         // unsigned Source | 
| 160 |         return true; | 
| 161 |     } | 
| 162 | }; | 
| 163 |  | 
| 164 | template <typename Target, typename Source, bool CanElide = IsSameType<Target, Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider; | 
| 165 | template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> { | 
| 166 |     static bool inBounds(Source) { return true; } | 
| 167 | }; | 
| 168 | template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> { | 
| 169 | }; | 
| 170 |  | 
| 171 | template <typename Target, typename Source> static inline bool isInBounds(Source value) | 
| 172 | { | 
| 173 |     return BoundsCheckElider<Target, Source>::inBounds(value); | 
| 174 | } | 
| 175 |  | 
| 176 | template <typename T> struct RemoveChecked { | 
| 177 |     typedef T CleanType; | 
| 178 |     static const CleanType DefaultValue = 0;     | 
| 179 | }; | 
| 180 |  | 
| 181 | template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > { | 
| 182 |     typedef typename RemoveChecked<T>::CleanType CleanType; | 
| 183 |     static const CleanType DefaultValue = 0; | 
| 184 | }; | 
| 185 |  | 
| 186 | template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > { | 
| 187 |     typedef typename RemoveChecked<T>::CleanType CleanType; | 
| 188 |     static const CleanType DefaultValue = 0; | 
| 189 | }; | 
| 190 |  | 
| 191 | // The ResultBase and SignednessSelector are used to workaround typeof not being | 
| 192 | // available in MSVC | 
| 193 | template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; | 
| 194 | template <typename U, typename V> struct ResultBase<U, V, true, false> { | 
| 195 |     typedef U ResultType; | 
| 196 | }; | 
| 197 |  | 
| 198 | template <typename U, typename V> struct ResultBase<U, V, false, false> { | 
| 199 |     typedef V ResultType; | 
| 200 | }; | 
| 201 |  | 
| 202 | template <typename U> struct ResultBase<U, U, false, true> { | 
| 203 |     typedef U ResultType; | 
| 204 | }; | 
| 205 |  | 
| 206 | template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector; | 
| 207 | template <typename U, typename V> struct SignednessSelector<U, V, true, true> { | 
| 208 |     typedef U ResultType; | 
| 209 | }; | 
| 210 |  | 
| 211 | template <typename U, typename V> struct SignednessSelector<U, V, false, false> { | 
| 212 |     typedef U ResultType; | 
| 213 | }; | 
| 214 |  | 
| 215 | template <typename U, typename V> struct SignednessSelector<U, V, true, false> { | 
| 216 |     typedef V ResultType; | 
| 217 | }; | 
| 218 |  | 
| 219 | template <typename U, typename V> struct SignednessSelector<U, V, false, true> { | 
| 220 |     typedef U ResultType; | 
| 221 | }; | 
| 222 |  | 
| 223 | template <typename U, typename V> struct ResultBase<U, V, false, true> { | 
| 224 |     typedef typename SignednessSelector<U, V>::ResultType ResultType; | 
| 225 | }; | 
| 226 |  | 
| 227 | template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> { | 
| 228 | }; | 
| 229 |  | 
| 230 | template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,  | 
| 231 |     bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations; | 
| 232 |  | 
| 233 | template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> { | 
| 234 |     // LHS and RHS are signed types | 
| 235 |  | 
| 236 |     // Helper function | 
| 237 |     static inline bool signsMatch(LHS lhs, RHS rhs) | 
| 238 |     { | 
| 239 |         return (lhs ^ rhs) >= 0; | 
| 240 |     } | 
| 241 |  | 
| 242 |     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 243 |     { | 
| 244 |         if (signsMatch(lhs, rhs)) { | 
| 245 |             if (lhs >= 0) { | 
| 246 |                 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs) | 
| 247 |                     return false; | 
| 248 |             } else { | 
| 249 |                 ResultType temp = lhs - std::numeric_limits<ResultType>::min(); | 
| 250 |                 if (rhs < -temp) | 
| 251 |                     return false; | 
| 252 |             } | 
| 253 |         } // if the signs do not match this operation can't overflow | 
| 254 |         result = lhs + rhs; | 
| 255 |         return true; | 
| 256 |     } | 
| 257 |  | 
| 258 |     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 259 |     { | 
| 260 |         if (!signsMatch(lhs, rhs)) { | 
| 261 |             if (lhs >= 0) { | 
| 262 |                 if (lhs > std::numeric_limits<ResultType>::max() + rhs) | 
| 263 |                     return false; | 
| 264 |             } else { | 
| 265 |                 if (rhs > std::numeric_limits<ResultType>::max() + lhs) | 
| 266 |                     return false; | 
| 267 |             } | 
| 268 |         } // if the signs match this operation can't overflow | 
| 269 |         result = lhs - rhs; | 
| 270 |         return true; | 
| 271 |     } | 
| 272 |  | 
| 273 |     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 274 |     { | 
| 275 |         if (signsMatch(lhs, rhs)) { | 
| 276 |             if (lhs >= 0) { | 
| 277 |                 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs) | 
| 278 |                     return false; | 
| 279 |             } else { | 
| 280 |                 if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultType>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::min()) | 
| 281 |                     return false; | 
| 282 |                 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs) | 
| 283 |                     return false; | 
| 284 |             } | 
| 285 |         } else { | 
| 286 |             if (lhs < 0) { | 
| 287 |                 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs)) | 
| 288 |                     return false; | 
| 289 |             } else { | 
| 290 |                 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs)) | 
| 291 |                     return false; | 
| 292 |             } | 
| 293 |         } | 
| 294 |         result = lhs * rhs; | 
| 295 |         return true; | 
| 296 |     } | 
| 297 |  | 
| 298 |     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } | 
| 299 |  | 
| 300 | }; | 
| 301 |  | 
| 302 | template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> { | 
| 303 |     // LHS and RHS are unsigned types so bounds checks are nice and easy | 
| 304 |     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 305 |     { | 
| 306 |         ResultType temp = lhs + rhs; | 
| 307 |         if (temp < lhs) | 
| 308 |             return false; | 
| 309 |         result = temp; | 
| 310 |         return true; | 
| 311 |     } | 
| 312 |  | 
| 313 |     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 314 |     { | 
| 315 |         ResultType temp = lhs - rhs; | 
| 316 |         if (temp > lhs) | 
| 317 |             return false; | 
| 318 |         result = temp; | 
| 319 |         return true; | 
| 320 |     } | 
| 321 |  | 
| 322 |     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN | 
| 323 |     { | 
| 324 |         if (!lhs || !rhs) { | 
| 325 |             result = 0; | 
| 326 |             return true; | 
| 327 |         } | 
| 328 |         if (std::numeric_limits<ResultType>::max() / lhs < rhs) | 
| 329 |             return false; | 
| 330 |         result = lhs * rhs; | 
| 331 |         return true; | 
| 332 |     } | 
| 333 |  | 
| 334 |     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } | 
| 335 |  | 
| 336 | }; | 
| 337 |  | 
| 338 | template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> { | 
| 339 |     static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) | 
| 340 |     { | 
| 341 |         int64_t temp = lhs + rhs; | 
| 342 |         if (temp < std::numeric_limits<ResultType>::min()) | 
| 343 |             return false; | 
| 344 |         if (temp > std::numeric_limits<ResultType>::max()) | 
| 345 |             return false; | 
| 346 |         result = static_cast<ResultType>(temp); | 
| 347 |         return true; | 
| 348 |     } | 
| 349 |      | 
| 350 |     static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) | 
| 351 |     { | 
| 352 |         int64_t temp = lhs - rhs; | 
| 353 |         if (temp < std::numeric_limits<ResultType>::min()) | 
| 354 |             return false; | 
| 355 |         if (temp > std::numeric_limits<ResultType>::max()) | 
| 356 |             return false; | 
| 357 |         result = static_cast<ResultType>(temp); | 
| 358 |         return true; | 
| 359 |     } | 
| 360 |  | 
| 361 |     static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) | 
| 362 |     { | 
| 363 |         int64_t temp = lhs * rhs; | 
| 364 |         if (temp < std::numeric_limits<ResultType>::min()) | 
| 365 |             return false; | 
| 366 |         if (temp > std::numeric_limits<ResultType>::max()) | 
| 367 |             return false; | 
| 368 |         result = static_cast<ResultType>(temp); | 
| 369 |         return true; | 
| 370 |     } | 
| 371 |  | 
| 372 |     static inline bool equals(int lhs, unsigned rhs) | 
| 373 |     { | 
| 374 |         return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs); | 
| 375 |     } | 
| 376 | }; | 
| 377 |  | 
| 378 | template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> { | 
| 379 |     static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) | 
| 380 |     { | 
| 381 |         return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result); | 
| 382 |     } | 
| 383 |      | 
| 384 |     static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) | 
| 385 |     { | 
| 386 |         return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result); | 
| 387 |     } | 
| 388 |  | 
| 389 |     static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) | 
| 390 |     { | 
| 391 |         return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result); | 
| 392 |     } | 
| 393 |  | 
| 394 |     static inline bool equals(unsigned lhs, int rhs) | 
| 395 |     { | 
| 396 |         return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs); | 
| 397 |     } | 
| 398 | }; | 
| 399 |  | 
| 400 | template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result) | 
| 401 | { | 
| 402 |     return ArithmeticOperations<U, V, R>::add(lhs, rhs, result); | 
| 403 | } | 
| 404 |  | 
| 405 | template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result) | 
| 406 | { | 
| 407 |     return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result); | 
| 408 | } | 
| 409 |  | 
| 410 | template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result) | 
| 411 | { | 
| 412 |     return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result); | 
| 413 | } | 
| 414 |  | 
| 415 | template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs) | 
| 416 | { | 
| 417 |     return ArithmeticOperations<U, V>::equals(lhs, rhs); | 
| 418 | } | 
| 419 |  | 
| 420 | enum ResultOverflowedTag { ResultOverflowed }; | 
| 421 |      | 
| 422 | // FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801 | 
| 423 | static inline bool workAroundClangBug() { return true; } | 
| 424 |  | 
| 425 | template <typename T, class OverflowHandler> class Checked : public OverflowHandler { | 
| 426 | public: | 
| 427 |     template <typename _T, class _OverflowHandler> friend class Checked; | 
| 428 |     Checked() | 
| 429 |         : m_value(0) | 
| 430 |     { | 
| 431 |     } | 
| 432 |  | 
| 433 |     Checked(const Checked &) = default; | 
| 434 |  | 
| 435 |  | 
| 436 |     Checked(ResultOverflowedTag) | 
| 437 |         : m_value(0) | 
| 438 |     { | 
| 439 |         // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801 | 
| 440 |         if (workAroundClangBug()) | 
| 441 |             this->overflowed(); | 
| 442 |     } | 
| 443 |  | 
| 444 |     template <typename U> Checked(U value) | 
| 445 |     { | 
| 446 |         if (!isInBounds<T>(value)) | 
| 447 |             this->overflowed(); | 
| 448 |         m_value = static_cast<T>(value); | 
| 449 |     } | 
| 450 |      | 
| 451 |     template <typename V> Checked(const Checked<T, V>& rhs) | 
| 452 |         : m_value(rhs.m_value) | 
| 453 |     { | 
| 454 |         if (rhs.hasOverflowed()) | 
| 455 |             this->overflowed(); | 
| 456 |     } | 
| 457 |      | 
| 458 |     template <typename U> Checked(const Checked<U, OverflowHandler>& rhs) | 
| 459 |         : OverflowHandler(rhs) | 
| 460 |     { | 
| 461 |         if (!isInBounds<T>(rhs.m_value)) | 
| 462 |             this->overflowed(); | 
| 463 |         m_value = static_cast<T>(rhs.m_value); | 
| 464 |     } | 
| 465 |      | 
| 466 |     template <typename U, typename V> Checked(const Checked<U, V>& rhs) | 
| 467 |     { | 
| 468 |         if (rhs.hasOverflowed()) | 
| 469 |             this->overflowed(); | 
| 470 |         if (!isInBounds<T>(rhs.m_value)) | 
| 471 |             this->overflowed(); | 
| 472 |         m_value = static_cast<T>(rhs.m_value); | 
| 473 |     } | 
| 474 |      | 
| 475 |     const Checked& operator=(Checked rhs) | 
| 476 |     { | 
| 477 |         this->clearOverflow(); | 
| 478 |         if (rhs.hasOverflowed()) | 
| 479 |             this->overflowed(); | 
| 480 |         m_value = static_cast<T>(rhs.m_value); | 
| 481 |         return *this; | 
| 482 |     } | 
| 483 |      | 
| 484 |     template <typename U> const Checked& operator=(U value) | 
| 485 |     { | 
| 486 |         return *this = Checked(value); | 
| 487 |     } | 
| 488 |      | 
| 489 |     template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs) | 
| 490 |     { | 
| 491 |         return *this = Checked(rhs); | 
| 492 |     } | 
| 493 |      | 
| 494 |     // prefix | 
| 495 |     const Checked& operator++() | 
| 496 |     { | 
| 497 |         if (m_value == std::numeric_limits<T>::max()) | 
| 498 |             this->overflowed(); | 
| 499 |         m_value++; | 
| 500 |         return *this; | 
| 501 |     } | 
| 502 |      | 
| 503 |     const Checked& operator--() | 
| 504 |     { | 
| 505 |         if (m_value == std::numeric_limits<T>::min()) | 
| 506 |             this->overflowed(); | 
| 507 |         m_value--; | 
| 508 |         return *this; | 
| 509 |     } | 
| 510 |      | 
| 511 |     // postfix operators | 
| 512 |     const Checked operator++(int) | 
| 513 |     { | 
| 514 |         if (m_value == std::numeric_limits<T>::max()) | 
| 515 |             this->overflowed(); | 
| 516 |         return Checked(m_value++); | 
| 517 |     } | 
| 518 |      | 
| 519 |     const Checked operator--(int) | 
| 520 |     { | 
| 521 |         if (m_value == std::numeric_limits<T>::min()) | 
| 522 |             this->overflowed(); | 
| 523 |         return Checked(m_value--); | 
| 524 |     } | 
| 525 |      | 
| 526 |     // Boolean operators | 
| 527 |     bool operator!() const | 
| 528 |     { | 
| 529 |         if (this->hasOverflowed()) | 
| 530 |             CRASH(); | 
| 531 |         return !m_value; | 
| 532 |     } | 
| 533 |  | 
| 534 |     typedef void* (Checked::*UnspecifiedBoolType); | 
| 535 |     operator UnspecifiedBoolType*() const | 
| 536 |     { | 
| 537 |         if (this->hasOverflowed()) | 
| 538 |             CRASH(); | 
| 539 |         return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; | 
| 540 |     } | 
| 541 |  | 
| 542 |     // Value accessors. unsafeGet() will crash if there's been an overflow. | 
| 543 |     T unsafeGet() const | 
| 544 |     { | 
| 545 |         if (this->hasOverflowed()) | 
| 546 |             CRASH(); | 
| 547 |         return m_value; | 
| 548 |     } | 
| 549 |      | 
| 550 |     inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN | 
| 551 |     { | 
| 552 |         value = m_value; | 
| 553 |         if (this->hasOverflowed()) | 
| 554 |             return CheckedState::DidOverflow; | 
| 555 |         return CheckedState::DidNotOverflow; | 
| 556 |     } | 
| 557 |  | 
| 558 |     // Mutating assignment | 
| 559 |     template <typename U> const Checked operator+=(U rhs) | 
| 560 |     { | 
| 561 |         if (!safeAdd(m_value, rhs, m_value)) | 
| 562 |             this->overflowed(); | 
| 563 |         return *this; | 
| 564 |     } | 
| 565 |  | 
| 566 |     template <typename U> const Checked operator-=(U rhs) | 
| 567 |     { | 
| 568 |         if (!safeSub(m_value, rhs, m_value)) | 
| 569 |             this->overflowed(); | 
| 570 |         return *this; | 
| 571 |     } | 
| 572 |  | 
| 573 |     template <typename U> const Checked operator*=(U rhs) | 
| 574 |     { | 
| 575 |         if (!safeMultiply(m_value, rhs, m_value)) | 
| 576 |             this->overflowed(); | 
| 577 |         return *this; | 
| 578 |     } | 
| 579 |  | 
| 580 |     const Checked operator*=(double rhs) | 
| 581 |     { | 
| 582 |         double result = rhs * m_value; | 
| 583 |         // Handle +/- infinity and NaN | 
| 584 |         if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result)) | 
| 585 |             this->overflowed(); | 
| 586 |         m_value = (T)result; | 
| 587 |         return *this; | 
| 588 |     } | 
| 589 |  | 
| 590 |     const Checked operator*=(float rhs) | 
| 591 |     { | 
| 592 |         return *this *= (double)rhs; | 
| 593 |     } | 
| 594 |      | 
| 595 |     template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs) | 
| 596 |     { | 
| 597 |         if (rhs.hasOverflowed()) | 
| 598 |             this->overflowed(); | 
| 599 |         return *this += rhs.m_value; | 
| 600 |     } | 
| 601 |  | 
| 602 |     template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs) | 
| 603 |     { | 
| 604 |         if (rhs.hasOverflowed()) | 
| 605 |             this->overflowed(); | 
| 606 |         return *this -= rhs.m_value; | 
| 607 |     } | 
| 608 |  | 
| 609 |     template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs) | 
| 610 |     { | 
| 611 |         if (rhs.hasOverflowed()) | 
| 612 |             this->overflowed(); | 
| 613 |         return *this *= rhs.m_value; | 
| 614 |     } | 
| 615 |  | 
| 616 |     // Equality comparisons | 
| 617 |     template <typename V> bool operator==(Checked<T, V> rhs) | 
| 618 |     { | 
| 619 |         return unsafeGet() == rhs.unsafeGet(); | 
| 620 |     } | 
| 621 |  | 
| 622 |     template <typename U> bool operator==(U rhs) | 
| 623 |     { | 
| 624 |         if (this->hasOverflowed()) | 
| 625 |             this->overflowed(); | 
| 626 |         return safeEquals(m_value, rhs); | 
| 627 |     } | 
| 628 |      | 
| 629 |     template <typename U, typename V> const Checked operator==(Checked<U, V> rhs) | 
| 630 |     { | 
| 631 |         return unsafeGet() == Checked(rhs.unsafeGet()); | 
| 632 |     } | 
| 633 |  | 
| 634 |     template <typename U> bool operator!=(U rhs) | 
| 635 |     { | 
| 636 |         return !(*this == rhs); | 
| 637 |     } | 
| 638 |  | 
| 639 | private: | 
| 640 |     // Disallow implicit conversion of floating point to integer types | 
| 641 |     Checked(float); | 
| 642 |     Checked(double); | 
| 643 |     void operator=(float); | 
| 644 |     void operator=(double); | 
| 645 |     void operator+=(float); | 
| 646 |     void operator+=(double); | 
| 647 |     void operator-=(float); | 
| 648 |     void operator-=(double); | 
| 649 |     T m_value; | 
| 650 | }; | 
| 651 |  | 
| 652 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) | 
| 653 | { | 
| 654 |     U x = 0; | 
| 655 |     V y = 0; | 
| 656 |     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow; | 
| 657 |     typename Result<U, V>::ResultType result = 0; | 
| 658 |     overflowed |= !safeAdd(x, y, result); | 
| 659 |     if (overflowed) | 
| 660 |         return ResultOverflowed; | 
| 661 |     return result; | 
| 662 | } | 
| 663 |  | 
| 664 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) | 
| 665 | { | 
| 666 |     U x = 0; | 
| 667 |     V y = 0; | 
| 668 |     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow; | 
| 669 |     typename Result<U, V>::ResultType result = 0; | 
| 670 |     overflowed |= !safeSub(x, y, result); | 
| 671 |     if (overflowed) | 
| 672 |         return ResultOverflowed; | 
| 673 |     return result; | 
| 674 | } | 
| 675 |  | 
| 676 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) | 
| 677 | { | 
| 678 |     U x = 0; | 
| 679 |     V y = 0; | 
| 680 |     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow; | 
| 681 |     typename Result<U, V>::ResultType result = 0; | 
| 682 |     overflowed |= !safeMultiply(x, y, result); | 
| 683 |     if (overflowed) | 
| 684 |         return ResultOverflowed; | 
| 685 |     return result; | 
| 686 | } | 
| 687 |  | 
| 688 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs) | 
| 689 | { | 
| 690 |     return lhs + Checked<V, OverflowHandler>(rhs); | 
| 691 | } | 
| 692 |  | 
| 693 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs) | 
| 694 | { | 
| 695 |     return lhs - Checked<V, OverflowHandler>(rhs); | 
| 696 | } | 
| 697 |  | 
| 698 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs) | 
| 699 | { | 
| 700 |     return lhs * Checked<V, OverflowHandler>(rhs); | 
| 701 | } | 
| 702 |  | 
| 703 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs) | 
| 704 | { | 
| 705 |     return Checked<U, OverflowHandler>(lhs) + rhs; | 
| 706 | } | 
| 707 |  | 
| 708 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs) | 
| 709 | { | 
| 710 |     return Checked<U, OverflowHandler>(lhs) - rhs; | 
| 711 | } | 
| 712 |  | 
| 713 | template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs) | 
| 714 | { | 
| 715 |     return Checked<U, OverflowHandler>(lhs) * rhs; | 
| 716 | } | 
| 717 |  | 
| 718 | } | 
| 719 |  | 
| 720 | using WTF::Checked; | 
| 721 | using WTF::CheckedState; | 
| 722 | using WTF::RecordOverflow; | 
| 723 |  | 
| 724 | #endif | 
| 725 |  |