LCOV - code coverage report
Current view: directory - objdir/dist/include - CheckedInt.h (source / functions) Found Hit Coverage
Test: app.info Lines: 77 28 36.4 %
Date: 2012-06-02 Functions: 148 16 10.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is the Mozilla Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Benoit Jacob <bjacob@mozilla.com>
      24                 :  *  Jeff Muizelaar <jmuizelaar@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #ifndef mozilla_CheckedInt_h
      41                 : #define mozilla_CheckedInt_h
      42                 : 
      43                 : #include "prtypes.h"
      44                 : 
      45                 : #include <climits>
      46                 : 
      47                 : namespace mozilla {
      48                 : 
      49                 : namespace CheckedInt_internal {
      50                 : 
      51                 : /* we don't want to use std::numeric_limits here because PRInt... types may not support it,
      52                 :  * depending on the platform, e.g. on certain platforms they use nonstandard built-in types
      53                 :  */
      54                 : 
      55                 : /*** Step 1: manually record information for all the types that we want to support
      56                 :  ***/
      57                 : 
      58                 : struct unsupported_type {};
      59                 : 
      60                 : template<typename T> struct integer_type_manually_recorded_info
      61                 : {
      62                 :     enum { is_supported = 0 };
      63                 :     typedef unsupported_type twice_bigger_type;
      64                 :     typedef unsupported_type unsigned_type;
      65                 : };
      66                 : 
      67                 : 
      68                 : #define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type)  \
      69                 : template<> struct integer_type_manually_recorded_info<T>       \
      70                 : {                                                              \
      71                 :     enum { is_supported = 1 };                                 \
      72                 :     typedef _twice_bigger_type twice_bigger_type;              \
      73                 :     typedef _unsigned_type unsigned_type;                      \
      74                 :     static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {}          \
      75                 : };
      76                 : 
      77                 : //                                 Type      Twice Bigger Type     Unsigned Type
      78                 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt8,   PRInt16,              PRUint8)
      79                 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint8,  PRUint16,             PRUint8)
      80                 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt16,  PRInt32,              PRUint16)
      81                 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint16, PRUint32,             PRUint16)
      82             325 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt32,  PRInt64,              PRUint32)
      83               0 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint32, PRUint64,             PRUint32)
      84               0 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt64,  unsupported_type,     PRUint64)
      85               0 : CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint64, unsupported_type,     PRUint64)
      86                 : 
      87                 : 
      88                 : /*** Step 2: record some info about a given integer type,
      89                 :  ***         including whether it is supported, whether a twice bigger integer type
      90                 :  ***         is supported, what that twice bigger type is, and some stuff as found
      91                 :  ***         in std::numeric_limits (which we don't use because PRInt.. types may
      92                 :  ***         not support it, if they are defined directly from compiler built-in types).
      93                 :  ***         We use function names min_value() and max_value() instead of min() and max()
      94                 :  ***         because of stupid min/max macros in Windows headers.
      95                 :  ***/
      96                 : 
      97                 : template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
      98                 : template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
      99                 : 
     100                 : template<typename T> struct integer_traits
     101                 : {
     102                 :     typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
     103                 :     typedef typename integer_type_manually_recorded_info<T>::unsigned_type unsigned_type;
     104                 : 
     105                 :     enum {
     106                 :         is_supported = integer_type_manually_recorded_info<T>::is_supported,
     107                 :         twice_bigger_type_is_supported
     108                 :             = is_unsupported_type<
     109                 :                   typename integer_type_manually_recorded_info<T>::twice_bigger_type
     110                 :               >::answer ? 0 : 1,
     111                 :         size = sizeof(T),
     112                 :         position_of_sign_bit = CHAR_BIT * size - 1,
     113                 :         is_signed = (T(-1) > T(0)) ? 0 : 1
     114                 :     };
     115                 : 
     116             650 :     static T min_value()
     117                 :     {
     118                 :         // bitwise ops may return a larger type, that's why we cast explicitly to T
     119                 :         // in C++, left bit shifts on signed values is undefined by the standard unless the shifted value is representable.
     120                 :         // notice that signed-to-unsigned conversions are always well-defined in the standard,
     121                 :         // as the value congruent to 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
     122                 :         // representable.
     123             650 :         return is_signed ? T(unsigned_type(1) << position_of_sign_bit) : T(0);
     124                 :     }
     125                 : 
     126             325 :     static T max_value()
     127                 :     {
     128             325 :         return ~min_value();
     129                 :     }
     130                 : };
     131                 : 
     132                 : /*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
     133                 :  ***/
     134                 : 
     135                 : // bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
     136                 : // the result is really of type T
     137                 : 
     138               0 : template<typename T> inline T has_sign_bit(T x)
     139                 : {
     140                 :     // in C++, right bit shifts on negative values is undefined by the standard.
     141                 :     // notice that signed-to-unsigned conversions are always well-defined in the standard,
     142                 :     // as the value congruent modulo 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
     143                 :     // representable. Here the unsigned-to-signed conversion is OK because the value (the result of the shift) is 0 or 1.
     144                 :     typedef typename integer_traits<T>::unsigned_type unsigned_T;
     145               0 :     return T(unsigned_T(x) >> integer_traits<T>::position_of_sign_bit);
     146                 : }
     147                 : 
     148               0 : template<typename T> inline T binary_complement(T x)
     149                 : {
     150               0 :     return ~x;
     151                 : }
     152                 : 
     153                 : template<typename T, typename U,
     154                 :          bool is_T_signed = integer_traits<T>::is_signed,
     155                 :          bool is_U_signed = integer_traits<U>::is_signed>
     156                 : struct is_in_range_impl {};
     157                 : 
     158                 : template<typename T, typename U>
     159                 : struct is_in_range_impl<T, U, true, true>
     160                 : {
     161             325 :     static T run(U x)
     162                 :     {
     163                 :         return (x <= integer_traits<T>::max_value()) &&
     164             325 :                (x >= integer_traits<T>::min_value());
     165                 :     }
     166                 : };
     167                 : 
     168                 : template<typename T, typename U>
     169                 : struct is_in_range_impl<T, U, false, false>
     170                 : {
     171               0 :     static T run(U x)
     172                 :     {
     173               0 :         return x <= integer_traits<T>::max_value();
     174                 :     }
     175                 : };
     176                 : 
     177                 : template<typename T, typename U>
     178                 : struct is_in_range_impl<T, U, true, false>
     179                 : {
     180               0 :     static T run(U x)
     181                 :     {
     182                 :         if (sizeof(T) > sizeof(U))
     183               0 :             return 1;
     184                 :         else
     185               0 :             return x <= U(integer_traits<T>::max_value());
     186                 :     }
     187                 : };
     188                 : 
     189                 : template<typename T, typename U>
     190                 : struct is_in_range_impl<T, U, false, true>
     191                 : {
     192               0 :     static T run(U x)
     193                 :     {
     194                 :         if (sizeof(T) >= sizeof(U))
     195               0 :             return x >= 0;
     196                 :         else
     197                 :             return (x >= 0) && (x <= U(integer_traits<T>::max_value()));
     198                 :     }
     199                 : };
     200                 : 
     201             325 : template<typename T, typename U> inline T is_in_range(U x)
     202                 : {
     203             325 :     return is_in_range_impl<T, U>::run(x);
     204                 : }
     205                 : 
     206               0 : template<typename T> inline T is_add_valid(T x, T y, T result)
     207                 : {
     208                 :     return integer_traits<T>::is_signed ?
     209                 :                         // addition is valid if the sign of x+y is equal to either that of x or that of y.
     210                 :                         // Beware! These bitwise operations can return a larger integer type, if T was a
     211                 :                         // small type like int8, so we explicitly cast to T.
     212                 :                         has_sign_bit(binary_complement(T((result^x) & (result^y))))
     213                 :                     :
     214               0 :                         binary_complement(x) >= y;
     215                 : }
     216                 : 
     217               0 : template<typename T> inline T is_sub_valid(T x, T y, T result)
     218                 : {
     219                 :     return integer_traits<T>::is_signed ?
     220                 :                         // substraction is valid if either x and y have same sign, or x-y and x have same sign
     221                 :                         has_sign_bit(binary_complement(T((result^x) & (x^y))))
     222                 :                     :
     223               0 :                         x >= y;
     224                 : }
     225                 : 
     226                 : template<typename T,
     227                 :          bool is_signed =  integer_traits<T>::is_signed,
     228                 :          bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
     229                 : struct is_mul_valid_impl {};
     230                 : 
     231                 : template<typename T, bool is_signed>
     232                 : struct is_mul_valid_impl<T, is_signed, true>
     233                 : {
     234             130 :     static T run(T x, T y)
     235                 :     {
     236                 :         typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
     237             130 :         twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
     238             130 :         return is_in_range<T>(product);
     239                 :     }
     240                 : };
     241                 : 
     242                 : template<typename T>
     243                 : struct is_mul_valid_impl<T, true, false>
     244                 : {
     245               0 :     static T run(T x, T y)
     246                 :     {
     247               0 :         const T max_value = integer_traits<T>::max_value();
     248               0 :         const T min_value = integer_traits<T>::min_value();
     249                 : 
     250               0 :         if (x == 0 || y == 0) return true;
     251                 : 
     252               0 :         if (x > 0) {
     253               0 :             if (y > 0)
     254               0 :                 return x <= max_value / y;
     255                 :             else
     256               0 :                 return y >= min_value / x;
     257                 :         } else {
     258               0 :             if (y > 0)
     259               0 :                 return x >= min_value / y;
     260                 :             else
     261               0 :                 return y >= max_value / x;
     262                 :         }
     263                 :     }
     264                 : };
     265                 : 
     266                 : template<typename T>
     267                 : struct is_mul_valid_impl<T, false, false>
     268                 : {
     269                 :     static T run(T x, T y)
     270                 :     {
     271                 :         const T max_value = integer_traits<T>::max_value();
     272                 :         if (x == 0 || y == 0) return true;
     273                 :         return x <= max_value / y;
     274                 :     }
     275                 : };
     276                 : 
     277             130 : template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
     278                 : {
     279             130 :     return is_mul_valid_impl<T>::run(x, y);
     280                 : }
     281                 : 
     282               0 : template<typename T> inline T is_div_valid(T x, T y)
     283                 : {
     284                 :     return integer_traits<T>::is_signed ?
     285                 :                         // keep in mind that min/-1 is invalid because abs(min)>max
     286                 :                         (y != 0) && (x != integer_traits<T>::min_value() || y != T(-1))
     287                 :                     :
     288               0 :                         y != 0;
     289                 : }
     290                 : 
     291                 : // this is just to shut up msvc warnings about negating unsigned ints.
     292                 : template<typename T, bool is_signed = integer_traits<T>::is_signed>
     293                 : struct opposite_if_signed_impl
     294                 : {
     295                 :     static T run(T x) { return -x; }
     296                 : };
     297                 : template<typename T>
     298                 : struct opposite_if_signed_impl<T, false>
     299                 : {
     300                 :     static T run(T x) { return x; }
     301                 : };
     302                 : template<typename T>
     303                 : inline T opposite_if_signed(T x) { return opposite_if_signed_impl<T>::run(x); }
     304                 : 
     305                 : 
     306                 : 
     307                 : } // end namespace CheckedInt_internal
     308                 : 
     309                 : 
     310                 : /*** Step 4: Now define the CheckedInt class.
     311                 :  ***/
     312                 : 
     313                 : /** \class CheckedInt
     314                 :   * \brief Integer wrapper class checking for integer overflow and other errors
     315                 :   * \param T the integer type to wrap. Can be any of PRInt8, PRUint8, PRInt16, PRUint16,
     316                 :   *          PRInt32, PRUint32, PRInt64, PRUint64.
     317                 :   *
     318                 :   * This class implements guarded integer arithmetic. Do a computation, check that
     319                 :   * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
     320                 :   * happened during this computation.
     321                 :   *
     322                 :   * The arithmetic operators in this class are guaranteed not to crash your app
     323                 :   * in case of a division by zero.
     324                 :   *
     325                 :   * For example, suppose that you want to implement a function that computes (x+y)/z,
     326                 :   * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
     327                 :   * You could code it as follows:
     328                 :     \code
     329                 :     bool compute_x_plus_y_over_z(PRInt32 x, PRInt32 y, PRInt32 z, PRInt32 *result)
     330                 :     {
     331                 :         CheckedInt<PRInt32> checked_result = (CheckedInt<PRInt32>(x) + y) / z;
     332                 :         *result = checked_result.value();
     333                 :         return checked_result.valid();
     334                 :     }
     335                 :     \endcode
     336                 :   *
     337                 :   * Implicit conversion from plain integers to checked integers is allowed. The plain integer
     338                 :   * is checked to be in range before being casted to the destination type. This means that the following
     339                 :   * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
     340                 :   * \code
     341                 :     CheckedInt<PRUint8> x(1);   // 1 is of type int, is found to be in range for PRUint8, x is valid
     342                 :     CheckedInt<PRUint8> x(-1);  // -1 is of type int, is found not to be in range for PRUint8, x is invalid
     343                 :     CheckedInt<PRInt8> x(-1);   // -1 is of type int, is found to be in range for PRInt8, x is valid
     344                 :     CheckedInt<PRInt8> x(PRInt16(1000)); // 1000 is of type PRInt16, is found not to be in range for PRInt8, x is invalid
     345                 :     CheckedInt<PRInt32> x(PRUint32(3123456789)); // 3123456789 is of type PRUint32, is found not to be in range
     346                 :                                              // for PRInt32, x is invalid
     347                 :   * \endcode
     348                 :   * Implicit conversion from
     349                 :   * checked integers to plain integers is not allowed. As shown in the
     350                 :   * above example, to get the value of a checked integer as a normal integer, call value().
     351                 :   *
     352                 :   * Arithmetic operations between checked and plain integers is allowed; the result type
     353                 :   * is the type of the checked integer.
     354                 :   *
     355                 :   * Checked integers of different types cannot be used in the same arithmetic expression.
     356                 :   *
     357                 :   * There are convenience typedefs for all PR integer types, of the following form (these are just 2 examples):
     358                 :     \code
     359                 :     typedef CheckedInt<PRInt32> CheckedInt32;
     360                 :     typedef CheckedInt<PRUint16> CheckedUint16;
     361                 :     \endcode
     362                 :   */
     363                 : template<typename T>
     364                 : class CheckedInt
     365                 : {
     366                 : protected:
     367                 :     T mValue;
     368                 :     T mIsValid; // stored as a T to limit the number of integer conversions when
     369                 :                 // evaluating nested arithmetic expressions.
     370                 : 
     371                 :     template<typename U>
     372             130 :     CheckedInt(U value, T isValid) : mValue(value), mIsValid(isValid)
     373                 :     {
     374             130 :         CheckedInt_internal::integer_type_manually_recorded_info<T>
     375                 :             ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
     376             130 :     }
     377                 : 
     378                 : public:
     379                 :     /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
     380                 :       * depending on whether the \a value is in range.
     381                 :       *
     382                 :       * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
     383                 :       * ensuring that no conversion is performed before this constructor is actually called.
     384                 :       * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
     385                 :       * valid.
     386                 :       */
     387                 :     template<typename U>
     388             195 :     CheckedInt(U value)
     389                 :         : mValue(T(value)),
     390             195 :           mIsValid(CheckedInt_internal::is_in_range<T>(value))
     391                 :     {
     392             195 :         CheckedInt_internal::integer_type_manually_recorded_info<T>
     393                 :             ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
     394             195 :     }
     395                 : 
     396                 :     /** Constructs a valid checked integer with initial value 0 */
     397               0 :     CheckedInt() : mValue(0), mIsValid(1)
     398                 :     {
     399               0 :         CheckedInt_internal::integer_type_manually_recorded_info<T>
     400                 :             ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
     401               0 :     }
     402                 : 
     403                 :     /** \returns the actual value */
     404               0 :     T value() const { return mValue; }
     405                 : 
     406                 :     /** \returns true if the checked integer is valid, i.e. is not the result
     407                 :       * of an invalid operation or of an operation involving an invalid checked integer
     408                 :       */
     409             130 :     bool valid() const
     410                 :     {
     411             130 :         return bool(mIsValid);
     412                 :     }
     413                 : 
     414                 :     /** \returns the sum. Checks for overflow. */
     415                 :     template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
     416                 :     /** Adds. Checks for overflow. \returns self reference */
     417                 :     template<typename U> CheckedInt& operator +=(U rhs);
     418                 :     /** \returns the difference. Checks for overflow. */
     419                 :     template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
     420                 :     /** Substracts. Checks for overflow. \returns self reference */
     421                 :     template<typename U> CheckedInt& operator -=(U rhs);
     422                 :     /** \returns the product. Checks for overflow. */
     423                 :     template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
     424                 :     /** Multiplies. Checks for overflow. \returns self reference */
     425                 :     template<typename U> CheckedInt& operator *=(U rhs);
     426                 :     /** \returns the quotient. Checks for overflow and for divide-by-zero. */
     427                 :     template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
     428                 :     /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
     429                 :     template<typename U> CheckedInt& operator /=(U rhs);
     430                 : 
     431                 :     /** \returns the opposite value. Checks for overflow. */
     432                 :     CheckedInt operator -() const
     433                 :     {
     434                 :         // circumvent msvc warning about - applied to unsigned int.
     435                 :         // if we're unsigned, the only valid case anyway is 0 in which case - is a no-op.
     436                 :         T result = CheckedInt_internal::opposite_if_signed(value());
     437                 :         /* give the compiler a good chance to perform RVO */
     438                 :         return CheckedInt(result,
     439                 :                           mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
     440                 :     }
     441                 : 
     442                 :     /** \returns true if the left and right hand sides are valid and have the same value. */
     443                 :     bool operator ==(const CheckedInt& other) const
     444                 :     {
     445                 :         return bool(mIsValid & other.mIsValid & (value() == other.mValue));
     446                 :     }
     447                 : 
     448                 :     /** prefix ++ */
     449               0 :     CheckedInt& operator++()
     450                 :     {
     451               0 :         *this = *this + 1;
     452               0 :         return *this;
     453                 :     }
     454                 : 
     455                 :     /** postfix ++ */
     456                 :     CheckedInt operator++(int)
     457                 :     {
     458                 :         CheckedInt tmp = *this;
     459                 :         *this = *this + 1;
     460                 :         return tmp;
     461                 :     }
     462                 : 
     463                 :     /** prefix -- */
     464                 :     CheckedInt& operator--()
     465                 :     {
     466                 :         *this = *this - 1;
     467                 :         return *this;
     468                 :     }
     469                 : 
     470                 :     /** postfix -- */
     471                 :     CheckedInt operator--(int)
     472                 :     {
     473                 :         CheckedInt tmp = *this;
     474                 :         *this = *this - 1;
     475                 :         return tmp;
     476                 :     }
     477                 : 
     478                 : private:
     479                 :     /** operator!= is disabled. Indeed, (a!=b) should be the same as !(a==b) but that
     480                 :       * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
     481                 :       */
     482                 :     template<typename U>
     483                 :     bool operator !=(U other) const { return !(*this == other); }
     484                 : };
     485                 : 
     486                 : #define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)               \
     487                 : template<typename T>                                          \
     488                 : inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
     489                 : {                                                                     \
     490                 :     T x = lhs.mValue;                                                \
     491                 :     T y = rhs.mValue;                                                \
     492                 :     T result = x OP y;                                                \
     493                 :     T is_op_valid                                                     \
     494                 :         = CheckedInt_internal::is_##NAME##_valid(x, y, result);       \
     495                 :     /* give the compiler a good chance to perform RVO */              \
     496                 :     return CheckedInt<T>(result,                                      \
     497                 :                          lhs.mIsValid & rhs.mIsValid & is_op_valid);  \
     498                 : }
     499                 : 
     500               0 : CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
     501               0 : CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
     502             130 : CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
     503                 : 
     504                 : // division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
     505                 : // because if rhs == 0, we are not allowed to even try to compute the quotient.
     506                 : template<typename T>
     507               0 : inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
     508                 : {
     509               0 :     T x = lhs.mValue;
     510               0 :     T y = rhs.mValue;
     511               0 :     T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
     512               0 :     T result = is_op_valid ? (x / y) : 0;
     513                 :     /* give the compiler a good chance to perform RVO */
     514                 :     return CheckedInt<T>(result,
     515               0 :                          lhs.mIsValid & rhs.mIsValid & is_op_valid);
     516                 : }
     517                 : 
     518                 : // implement cast_to_CheckedInt<T>(x), making sure that
     519                 : //  - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
     520                 : //  - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
     521                 : 
     522                 : template<typename T, typename U>
     523                 : struct cast_to_CheckedInt_impl
     524                 : {
     525                 :     typedef CheckedInt<T> return_type;
     526             130 :     static CheckedInt<T> run(U u) { return u; }
     527                 : };
     528                 : 
     529                 : template<typename T>
     530                 : struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
     531                 : {
     532                 :     typedef const CheckedInt<T>& return_type;
     533                 :     static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
     534                 : };
     535                 : 
     536                 : template<typename T, typename U>
     537                 : inline typename cast_to_CheckedInt_impl<T, U>::return_type
     538             130 : cast_to_CheckedInt(U u)
     539                 : {
     540             130 :     return cast_to_CheckedInt_impl<T, U>::run(u);
     541                 : }
     542                 : 
     543                 : #define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
     544                 : template<typename T>                                          \
     545                 : template<typename U>                                          \
     546                 : CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs)    \
     547                 : {                                                             \
     548                 :     *this = *this OP cast_to_CheckedInt<T>(rhs);                 \
     549                 :     return *this;                                             \
     550                 : }                                                             \
     551                 : template<typename T, typename U>                              \
     552                 : inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
     553                 : {                                                             \
     554                 :     return lhs OP cast_to_CheckedInt<T>(rhs);                    \
     555                 : }                                                             \
     556                 : template<typename T, typename U>                              \
     557                 : inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
     558                 : {                                                             \
     559                 :     return cast_to_CheckedInt<T>(lhs) OP rhs;                    \
     560                 : }
     561                 : 
     562               0 : CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
     563             130 : CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
     564               0 : CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
     565               0 : CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
     566                 : 
     567                 : template<typename T, typename U>
     568                 : inline bool operator ==(const CheckedInt<T> &lhs, U rhs)
     569                 : {
     570                 :     return lhs == cast_to_CheckedInt<T>(rhs);
     571                 : }
     572                 : 
     573                 : template<typename T, typename U>
     574                 : inline bool operator ==(U  lhs, const CheckedInt<T> &rhs)
     575                 : {
     576                 :     return cast_to_CheckedInt<T>(lhs) == rhs;
     577                 : }
     578                 : 
     579                 : // convenience typedefs.
     580                 : // the use of a macro here helps make sure that we don't let a typo slip into some of these.
     581                 : #define CHECKEDINT_MAKE_TYPEDEF(Type) \
     582                 : typedef CheckedInt<PR##Type> Checked##Type;
     583                 : 
     584                 : CHECKEDINT_MAKE_TYPEDEF(Int8)
     585                 : CHECKEDINT_MAKE_TYPEDEF(Uint8)
     586                 : CHECKEDINT_MAKE_TYPEDEF(Int16)
     587                 : CHECKEDINT_MAKE_TYPEDEF(Uint16)
     588                 : CHECKEDINT_MAKE_TYPEDEF(Int32)
     589                 : CHECKEDINT_MAKE_TYPEDEF(Uint32)
     590                 : CHECKEDINT_MAKE_TYPEDEF(Int64)
     591                 : CHECKEDINT_MAKE_TYPEDEF(Uint64)
     592                 : 
     593                 : } // end namespace mozilla
     594                 : 
     595                 : #endif /* mozilla_CheckedInt_h */

Generated by: LCOV version 1.7