LCOV - code coverage report
Current view: top level - mfbt - CheckedInt.h (source / functions) Hit Total Coverage
Test: output.info Lines: 59 92 64.1 %
Date: 2017-07-14 16:53:18 Functions: 120 278 43.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13