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

Generated by: LCOV version 1.13-14-ga5dd952