Home | History | Annotate | Download | only in wtf
      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 protected:
     78     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(ResultOverflowedTag)
    434         : m_value(0)
    435     {
    436         // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
    437         if (workAroundClangBug())
    438             this->overflowed();
    439     }
    440 
    441     template <typename U> Checked(U value)
    442     {
    443         if (!isInBounds<T>(value))
    444             this->overflowed();
    445         m_value = static_cast<T>(value);
    446     }
    447 
    448     template <typename V> Checked(const Checked<T, V>& rhs)
    449         : m_value(rhs.m_value)
    450     {
    451         if (rhs.hasOverflowed())
    452             this->overflowed();
    453     }
    454 
    455     template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
    456         : OverflowHandler(rhs)
    457     {
    458         if (!isInBounds<T>(rhs.m_value))
    459             this->overflowed();
    460         m_value = static_cast<T>(rhs.m_value);
    461     }
    462 
    463     template <typename U, typename V> Checked(const Checked<U, V>& rhs)
    464     {
    465         if (rhs.hasOverflowed())
    466             this->overflowed();
    467         if (!isInBounds<T>(rhs.m_value))
    468             this->overflowed();
    469         m_value = static_cast<T>(rhs.m_value);
    470     }
    471 
    472     const Checked& operator=(Checked rhs)
    473     {
    474         this->clearOverflow();
    475         if (rhs.hasOverflowed())
    476             this->overflowed();
    477         m_value = static_cast<T>(rhs.m_value);
    478         return *this;
    479     }
    480 
    481     template <typename U> const Checked& operator=(U value)
    482     {
    483         return *this = Checked(value);
    484     }
    485 
    486     template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
    487     {
    488         return *this = Checked(rhs);
    489     }
    490 
    491     // prefix
    492     const Checked& operator++()
    493     {
    494         if (m_value == std::numeric_limits<T>::max())
    495             this->overflowed();
    496         m_value++;
    497         return *this;
    498     }
    499 
    500     const Checked& operator--()
    501     {
    502         if (m_value == std::numeric_limits<T>::min())
    503             this->overflowed();
    504         m_value--;
    505         return *this;
    506     }
    507 
    508     // postfix operators
    509     const Checked operator++(int)
    510     {
    511         if (m_value == std::numeric_limits<T>::max())
    512             this->overflowed();
    513         return Checked(m_value++);
    514     }
    515 
    516     const Checked operator--(int)
    517     {
    518         if (m_value == std::numeric_limits<T>::min())
    519             this->overflowed();
    520         return Checked(m_value--);
    521     }
    522 
    523     // Boolean operators
    524     bool operator!() const
    525     {
    526         if (this->hasOverflowed())
    527             CRASH();
    528         return !m_value;
    529     }
    530 
    531     typedef void* (Checked::*UnspecifiedBoolType);
    532     operator UnspecifiedBoolType*() const
    533     {
    534         if (this->hasOverflowed())
    535             CRASH();
    536         return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
    537     }
    538 
    539     // Value accessors. unsafeGet() will crash if there's been an overflow.
    540     T unsafeGet() const
    541     {
    542         if (this->hasOverflowed())
    543             CRASH();
    544         return m_value;
    545     }
    546 
    547     inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
    548     {
    549         value = m_value;
    550         if (this->hasOverflowed())
    551             return CheckedState::DidOverflow;
    552         return CheckedState::DidNotOverflow;
    553     }
    554 
    555     // Mutating assignment
    556     template <typename U> const Checked operator+=(U rhs)
    557     {
    558         if (!safeAdd(m_value, rhs, m_value))
    559             this->overflowed();
    560         return *this;
    561     }
    562 
    563     template <typename U> const Checked operator-=(U rhs)
    564     {
    565         if (!safeSub(m_value, rhs, m_value))
    566             this->overflowed();
    567         return *this;
    568     }
    569 
    570     template <typename U> const Checked operator*=(U rhs)
    571     {
    572         if (!safeMultiply(m_value, rhs, m_value))
    573             this->overflowed();
    574         return *this;
    575     }
    576 
    577     const Checked operator*=(double rhs)
    578     {
    579         double result = rhs * m_value;
    580         // Handle +/- infinity and NaN
    581         if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
    582             this->overflowed();
    583         m_value = (T)result;
    584         return *this;
    585     }
    586 
    587     const Checked operator*=(float rhs)
    588     {
    589         return *this *= (double)rhs;
    590     }
    591 
    592     template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
    593     {
    594         if (rhs.hasOverflowed())
    595             this->overflowed();
    596         return *this += rhs.m_value;
    597     }
    598 
    599     template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
    600     {
    601         if (rhs.hasOverflowed())
    602             this->overflowed();
    603         return *this -= rhs.m_value;
    604     }
    605 
    606     template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
    607     {
    608         if (rhs.hasOverflowed())
    609             this->overflowed();
    610         return *this *= rhs.m_value;
    611     }
    612 
    613     // Equality comparisons
    614     template <typename V> bool operator==(Checked<T, V> rhs)
    615     {
    616         return unsafeGet() == rhs.unsafeGet();
    617     }
    618 
    619     template <typename U> bool operator==(U rhs)
    620     {
    621         if (this->hasOverflowed())
    622             this->overflowed();
    623         return safeEquals(m_value, rhs);
    624     }
    625 
    626     template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
    627     {
    628         return unsafeGet() == Checked(rhs.unsafeGet());
    629     }
    630 
    631     template <typename U> bool operator!=(U rhs)
    632     {
    633         return !(*this == rhs);
    634     }
    635 
    636 private:
    637     // Disallow implicit conversion of floating point to integer types
    638     Checked(float);
    639     Checked(double);
    640     void operator=(float);
    641     void operator=(double);
    642     void operator+=(float);
    643     void operator+=(double);
    644     void operator-=(float);
    645     void operator-=(double);
    646     T m_value;
    647 };
    648 
    649 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)
    650 {
    651     U x = 0;
    652     V y = 0;
    653     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    654     typename Result<U, V>::ResultType result = 0;
    655     overflowed |= !safeAdd(x, y, result);
    656     if (overflowed)
    657         return ResultOverflowed;
    658     return result;
    659 }
    660 
    661 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)
    662 {
    663     U x = 0;
    664     V y = 0;
    665     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    666     typename Result<U, V>::ResultType result = 0;
    667     overflowed |= !safeSub(x, y, result);
    668     if (overflowed)
    669         return ResultOverflowed;
    670     return result;
    671 }
    672 
    673 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)
    674 {
    675     U x = 0;
    676     V y = 0;
    677     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    678     typename Result<U, V>::ResultType result = 0;
    679     overflowed |= !safeMultiply(x, y, result);
    680     if (overflowed)
    681         return ResultOverflowed;
    682     return result;
    683 }
    684 
    685 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
    686 {
    687     return lhs + Checked<V, OverflowHandler>(rhs);
    688 }
    689 
    690 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
    691 {
    692     return lhs - Checked<V, OverflowHandler>(rhs);
    693 }
    694 
    695 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
    696 {
    697     return lhs * Checked<V, OverflowHandler>(rhs);
    698 }
    699 
    700 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
    701 {
    702     return Checked<U, OverflowHandler>(lhs) + rhs;
    703 }
    704 
    705 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
    706 {
    707     return Checked<U, OverflowHandler>(lhs) - rhs;
    708 }
    709 
    710 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
    711 {
    712     return Checked<U, OverflowHandler>(lhs) * rhs;
    713 }
    714 
    715 }
    716 
    717 using WTF::Checked;
    718 using WTF::CheckedState;
    719 using WTF::RecordOverflow;
    720 
    721 #endif
    722