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