Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / mfbt / CheckedInt.h
blob8e1be4b4b3e7e764fa1a2673b6c016d7a2dec8ba
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/. */
7 /* Provides checked integers, detecting integer overflow and divide-by-0. */
9 #ifndef mozilla_CheckedInt_h
10 #define mozilla_CheckedInt_h
12 #include <stdint.h>
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/IntegerTypeTraits.h"
17 namespace mozilla {
19 template<typename T> class CheckedInt;
21 namespace detail {
24 * Step 1: manually record supported types
26 * What's nontrivial here is that there are different families of integer
27 * types: basic integer types and stdint types. It is merrily undefined which
28 * types from one family may be just typedefs for a type from another family.
30 * For example, on GCC 4.6, aside from the basic integer types, the only other
31 * type that isn't just a typedef for some of them, is int8_t.
34 struct UnsupportedType {};
36 template<typename IntegerType>
37 struct IsSupportedPass2
39 static const bool value = false;
42 template<typename IntegerType>
43 struct IsSupported
45 static const bool value = IsSupportedPass2<IntegerType>::value;
48 template<>
49 struct IsSupported<int8_t>
50 { static const bool value = true; };
52 template<>
53 struct IsSupported<uint8_t>
54 { static const bool value = true; };
56 template<>
57 struct IsSupported<int16_t>
58 { static const bool value = true; };
60 template<>
61 struct IsSupported<uint16_t>
62 { static const bool value = true; };
64 template<>
65 struct IsSupported<int32_t>
66 { static const bool value = true; };
68 template<>
69 struct IsSupported<uint32_t>
70 { static const bool value = true; };
72 template<>
73 struct IsSupported<int64_t>
74 { static const bool value = true; };
76 template<>
77 struct IsSupported<uint64_t>
78 { static const bool value = true; };
81 template<>
82 struct IsSupportedPass2<char>
83 { static const bool value = true; };
85 template<>
86 struct IsSupportedPass2<signed char>
87 { static const bool value = true; };
89 template<>
90 struct IsSupportedPass2<unsigned char>
91 { static const bool value = true; };
93 template<>
94 struct IsSupportedPass2<short>
95 { static const bool value = true; };
97 template<>
98 struct IsSupportedPass2<unsigned short>
99 { static const bool value = true; };
101 template<>
102 struct IsSupportedPass2<int>
103 { static const bool value = true; };
105 template<>
106 struct IsSupportedPass2<unsigned int>
107 { static const bool value = true; };
109 template<>
110 struct IsSupportedPass2<long>
111 { static const bool value = true; };
113 template<>
114 struct IsSupportedPass2<unsigned long>
115 { static const bool value = true; };
117 template<>
118 struct IsSupportedPass2<long long>
119 { static const bool value = true; };
121 template<>
122 struct IsSupportedPass2<unsigned long long>
123 { static const bool value = true; };
126 * Step 2: Implement the actual validity checks.
128 * Ideas taken from IntegerLib, code different.
131 template<typename IntegerType, size_t Size = sizeof(IntegerType)>
132 struct TwiceBiggerType
134 typedef typename detail::StdintTypeForSizeAndSignedness<
135 sizeof(IntegerType) * 2,
136 IsSigned<IntegerType>::value
137 >::Type Type;
140 template<typename IntegerType>
141 struct TwiceBiggerType<IntegerType, 8>
143 typedef UnsupportedType Type;
146 template<typename T>
147 inline bool
148 HasSignBit(T aX)
150 // In C++, right bit shifts on negative values is undefined by the standard.
151 // Notice that signed-to-unsigned conversions are always well-defined in the
152 // standard, as the value congruent modulo 2**n as expected. By contrast,
153 // unsigned-to-signed is only well-defined if the value is representable.
154 return bool(typename MakeUnsigned<T>::Type(aX) >>
155 PositionOfSignBit<T>::value);
158 // Bitwise ops may return a larger type, so it's good to use this inline
159 // helper guaranteeing that the result is really of type T.
160 template<typename T>
161 inline T
162 BinaryComplement(T aX)
164 return ~aX;
167 template<typename T,
168 typename U,
169 bool IsTSigned = IsSigned<T>::value,
170 bool IsUSigned = IsSigned<U>::value>
171 struct DoesRangeContainRange
175 template<typename T, typename U, bool Signedness>
176 struct DoesRangeContainRange<T, U, Signedness, Signedness>
178 static const bool value = sizeof(T) >= sizeof(U);
181 template<typename T, typename U>
182 struct DoesRangeContainRange<T, U, true, false>
184 static const bool value = sizeof(T) > sizeof(U);
187 template<typename T, typename U>
188 struct DoesRangeContainRange<T, U, false, true>
190 static const bool value = false;
193 template<typename T,
194 typename U,
195 bool IsTSigned = IsSigned<T>::value,
196 bool IsUSigned = IsSigned<U>::value,
197 bool DoesTRangeContainURange = DoesRangeContainRange<T, U>::value>
198 struct IsInRangeImpl {};
200 template<typename T, typename U, bool IsTSigned, bool IsUSigned>
201 struct IsInRangeImpl<T, U, IsTSigned, IsUSigned, true>
203 static bool run(U)
205 return true;
209 template<typename T, typename U>
210 struct IsInRangeImpl<T, U, true, true, false>
212 static bool run(U aX)
214 return aX <= MaxValue<T>::value && aX >= MinValue<T>::value;
218 template<typename T, typename U>
219 struct IsInRangeImpl<T, U, false, false, false>
221 static bool run(U aX)
223 return aX <= MaxValue<T>::value;
227 template<typename T, typename U>
228 struct IsInRangeImpl<T, U, true, false, false>
230 static bool run(U aX)
232 return sizeof(T) > sizeof(U) || aX <= U(MaxValue<T>::value);
236 template<typename T, typename U>
237 struct IsInRangeImpl<T, U, false, true, false>
239 static bool run(U aX)
241 return sizeof(T) >= sizeof(U)
242 ? aX >= 0
243 : aX >= 0 && aX <= U(MaxValue<T>::value);
247 template<typename T, typename U>
248 inline bool
249 IsInRange(U aX)
251 return IsInRangeImpl<T, U>::run(aX);
254 template<typename T>
255 inline bool
256 IsAddValid(T aX, T aY)
258 // Addition is valid if the sign of aX+aY is equal to either that of aX or
259 // that of aY. Since the value of aX+aY is undefined if we have a signed
260 // type, we compute it using the unsigned type of the same size. Beware!
261 // These bitwise operations can return a larger integer type, if T was a
262 // small type like int8_t, so we explicitly cast to T.
264 typename MakeUnsigned<T>::Type ux = aX;
265 typename MakeUnsigned<T>::Type uy = aY;
266 typename MakeUnsigned<T>::Type result = ux + uy;
267 return IsSigned<T>::value
268 ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY))))
269 : BinaryComplement(aX) >= aY;
272 template<typename T>
273 inline bool
274 IsSubValid(T aX, T aY)
276 // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX
277 // have same sign. Since the value of aX-aY is undefined if we have a signed
278 // type, we compute it using the unsigned type of the same size.
279 typename MakeUnsigned<T>::Type ux = aX;
280 typename MakeUnsigned<T>::Type uy = aY;
281 typename MakeUnsigned<T>::Type result = ux - uy;
283 return IsSigned<T>::value
284 ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY))))
285 : aX >= aY;
288 template<typename T,
289 bool IsTSigned = IsSigned<T>::value,
290 bool TwiceBiggerTypeIsSupported =
291 IsSupported<typename TwiceBiggerType<T>::Type>::value>
292 struct IsMulValidImpl {};
294 template<typename T, bool IsTSigned>
295 struct IsMulValidImpl<T, IsTSigned, true>
297 static bool run(T aX, T aY)
299 typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
300 TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY);
301 return IsInRange<T>(product);
305 template<typename T>
306 struct IsMulValidImpl<T, true, false>
308 static bool run(T aX, T aY)
310 const T max = MaxValue<T>::value;
311 const T min = MinValue<T>::value;
313 if (aX == 0 || aY == 0) {
314 return true;
316 if (aX > 0) {
317 return aY > 0
318 ? aX <= max / aY
319 : aY >= min / aX;
322 // If we reach this point, we know that aX < 0.
323 return aY > 0
324 ? aX >= min / aY
325 : aY >= max / aX;
329 template<typename T>
330 struct IsMulValidImpl<T, false, false>
332 static bool run(T aX, T aY)
334 return aY == 0 || aX <= MaxValue<T>::value / aY;
338 template<typename T>
339 inline bool
340 IsMulValid(T aX, T aY)
342 return IsMulValidImpl<T>::run(aX, aY);
345 template<typename T>
346 inline bool
347 IsDivValid(T aX, T aY)
349 // Keep in mind that in the signed case, min/-1 is invalid because
350 // abs(min)>max.
351 return aY != 0 &&
352 !(IsSigned<T>::value && aX == MinValue<T>::value && aY == T(-1));
355 template<typename T, bool IsTSigned = IsSigned<T>::value>
356 struct IsModValidImpl;
358 template<typename T>
359 inline bool
360 IsModValid(T aX, T aY)
362 return IsModValidImpl<T>::run(aX, aY);
366 * Mod is pretty simple.
367 * For now, let's just use the ANSI C definition:
368 * If aX or aY are negative, the results are implementation defined.
369 * Consider these invalid.
370 * Undefined for aY=0.
371 * The result will never exceed either aX or aY.
373 * Checking that aX>=0 is a warning when T is unsigned.
376 template<typename T>
377 struct IsModValidImpl<T, false>
379 static inline bool run(T aX, T aY)
381 return aY >= 1;
385 template<typename T>
386 struct IsModValidImpl<T, true>
388 static inline bool run(T aX, T aY)
390 if (aX < 0) {
391 return false;
393 return aY >= 1;
397 template<typename T, bool IsSigned = IsSigned<T>::value>
398 struct NegateImpl;
400 template<typename T>
401 struct NegateImpl<T, false>
403 static CheckedInt<T> negate(const CheckedInt<T>& aVal)
405 // Handle negation separately for signed/unsigned, for simpler code and to
406 // avoid an MSVC warning negating an unsigned value.
407 return CheckedInt<T>(0, aVal.isValid() && aVal.mValue == 0);
411 template<typename T>
412 struct NegateImpl<T, true>
414 static CheckedInt<T> negate(const CheckedInt<T>& aVal)
416 // Watch out for the min-value, which (with twos-complement) can't be
417 // negated as -min-value is then (max-value + 1).
418 if (!aVal.isValid() || aVal.mValue == MinValue<T>::value) {
419 return CheckedInt<T>(aVal.mValue, false);
421 return CheckedInt<T>(-aVal.mValue, true);
425 } // namespace detail
429 * Step 3: Now define the CheckedInt class.
433 * @class CheckedInt
434 * @brief Integer wrapper class checking for integer overflow and other errors
435 * @param T the integer type to wrap. Can be any type among the following:
436 * - any basic integer type such as |int|
437 * - any stdint type such as |int8_t|
439 * This class implements guarded integer arithmetic. Do a computation, check
440 * that isValid() returns true, you then have a guarantee that no problem, such
441 * as integer overflow, happened during this computation, and you can call
442 * value() to get the plain integer value.
444 * The arithmetic operators in this class are guaranteed not to raise a signal
445 * (e.g. in case of a division by zero).
447 * For example, suppose that you want to implement a function that computes
448 * (aX+aY)/aZ, that doesn't crash if aZ==0, and that reports on error (divide by
449 * zero or integer overflow). You could code it as follows:
450 @code
451 bool computeXPlusYOverZ(int aX, int aY, int aZ, int* aResult)
453 CheckedInt<int> checkedResult = (CheckedInt<int>(aX) + aY) / aZ;
454 if (checkedResult.isValid()) {
455 *aResult = checkedResult.value();
456 return true;
457 } else {
458 return false;
461 @endcode
463 * Implicit conversion from plain integers to checked integers is allowed. The
464 * plain integer is checked to be in range before being casted to the
465 * destination type. This means that the following lines all compile, and the
466 * resulting CheckedInts are correctly detected as valid or invalid:
467 * @code
468 // 1 is of type int, is found to be in range for uint8_t, x is valid
469 CheckedInt<uint8_t> x(1);
470 // -1 is of type int, is found not to be in range for uint8_t, x is invalid
471 CheckedInt<uint8_t> x(-1);
472 // -1 is of type int, is found to be in range for int8_t, x is valid
473 CheckedInt<int8_t> x(-1);
474 // 1000 is of type int16_t, is found not to be in range for int8_t,
475 // x is invalid
476 CheckedInt<int8_t> x(int16_t(1000));
477 // 3123456789 is of type uint32_t, is found not to be in range for int32_t,
478 // x is invalid
479 CheckedInt<int32_t> x(uint32_t(3123456789));
480 * @endcode
481 * Implicit conversion from
482 * checked integers to plain integers is not allowed. As shown in the
483 * above example, to get the value of a checked integer as a normal integer,
484 * call value().
486 * Arithmetic operations between checked and plain integers is allowed; the
487 * result type is the type of the checked integer.
489 * Checked integers of different types cannot be used in the same arithmetic
490 * expression.
492 * There are convenience typedefs for all stdint types, of the following form
493 * (these are just 2 examples):
494 @code
495 typedef CheckedInt<int32_t> CheckedInt32;
496 typedef CheckedInt<uint16_t> CheckedUint16;
497 @endcode
499 template<typename T>
500 class CheckedInt
502 protected:
503 T mValue;
504 bool mIsValid;
506 template<typename U>
507 CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid)
509 static_assert(detail::IsSupported<T>::value &&
510 detail::IsSupported<U>::value,
511 "This type is not supported by CheckedInt");
514 friend struct detail::NegateImpl<T>;
516 public:
518 * Constructs a checked integer with given @a value. The checked integer is
519 * initialized as valid or invalid depending on whether the @a value
520 * is in range.
522 * This constructor is not explicit. Instead, the type of its argument is a
523 * separate template parameter, ensuring that no conversion is performed
524 * before this constructor is actually called. As explained in the above
525 * documentation for class CheckedInt, this constructor checks that its
526 * argument is valid.
528 template<typename U>
529 CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
530 : mValue(T(aValue)),
531 mIsValid(detail::IsInRange<T>(aValue))
533 static_assert(detail::IsSupported<T>::value &&
534 detail::IsSupported<U>::value,
535 "This type is not supported by CheckedInt");
538 template<typename U>
539 friend class CheckedInt;
541 template<typename U>
542 CheckedInt<U> toChecked() const
544 CheckedInt<U> ret(mValue);
545 ret.mIsValid = ret.mIsValid && mIsValid;
546 return ret;
549 /** Constructs a valid checked integer with initial value 0 */
550 CheckedInt() : mValue(0), mIsValid(true)
552 static_assert(detail::IsSupported<T>::value,
553 "This type is not supported by CheckedInt");
556 /** @returns the actual value */
557 T value() const
559 MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
560 return mValue;
564 * @returns true if the checked integer is valid, i.e. is not the result
565 * of an invalid operation or of an operation involving an invalid checked
566 * integer
568 bool isValid() const
570 return mIsValid;
573 template<typename U>
574 friend CheckedInt<U> operator +(const CheckedInt<U>& aLhs,
575 const CheckedInt<U>& aRhs);
576 template<typename U>
577 CheckedInt& operator +=(U aRhs);
578 CheckedInt& operator +=(const CheckedInt<T>& aRhs);
580 template<typename U>
581 friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
582 const CheckedInt<U>& aRhs);
583 template<typename U>
584 CheckedInt& operator -=(U aRhs);
585 CheckedInt& operator -=(const CheckedInt<T>& aRhs);
587 template<typename U>
588 friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
589 const CheckedInt<U>& aRhs);
590 template<typename U>
591 CheckedInt& operator *=(U aRhs);
592 CheckedInt& operator *=(const CheckedInt<T>& aRhs);
594 template<typename U>
595 friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
596 const CheckedInt<U>& aRhs);
597 template<typename U>
598 CheckedInt& operator /=(U aRhs);
599 CheckedInt& operator /=(const CheckedInt<T>& aRhs);
601 template<typename U>
602 friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
603 const CheckedInt<U>& aRhs);
604 template<typename U>
605 CheckedInt& operator %=(U aRhs);
606 CheckedInt& operator %=(const CheckedInt<T>& aRhs);
608 CheckedInt operator -() const
610 return detail::NegateImpl<T>::negate(*this);
614 * @returns true if the left and right hand sides are valid
615 * and have the same value.
617 * Note that these semantics are the reason why we don't offer
618 * a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
619 * but that would mean that whenever a or b is invalid, a!=b
620 * is always true, which would be very confusing.
622 * For similar reasons, operators <, >, <=, >= would be very tricky to
623 * specify, so we just avoid offering them.
625 * Notice that these == semantics are made more reasonable by these facts:
626 * 1. a==b implies equality at the raw data level
627 * (the converse is false, as a==b is never true among invalids)
628 * 2. This is similar to the behavior of IEEE floats, where a==b
629 * means that a and b have the same value *and* neither is NaN.
631 bool operator ==(const CheckedInt& aOther) const
633 return mIsValid && aOther.mIsValid && mValue == aOther.mValue;
636 /** prefix ++ */
637 CheckedInt& operator++()
639 *this += 1;
640 return *this;
643 /** postfix ++ */
644 CheckedInt operator++(int)
646 CheckedInt tmp = *this;
647 *this += 1;
648 return tmp;
651 /** prefix -- */
652 CheckedInt& operator--()
654 *this -= 1;
655 return *this;
658 /** postfix -- */
659 CheckedInt operator--(int)
661 CheckedInt tmp = *this;
662 *this -= 1;
663 return tmp;
666 private:
668 * The !=, <, <=, >, >= operators are disabled:
669 * see the comment on operator==.
671 template<typename U> bool operator !=(U aOther) const = delete;
672 template<typename U> bool operator < (U aOther) const = delete;
673 template<typename U> bool operator <=(U aOther) const = delete;
674 template<typename U> bool operator > (U aOther) const = delete;
675 template<typename U> bool operator >=(U aOther) const = delete;
678 #define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
679 template<typename T> \
680 inline CheckedInt<T> \
681 operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
683 if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
684 return CheckedInt<T>(0, false); \
686 return CheckedInt<T>(aLhs.mValue OP aRhs.mValue, \
687 aLhs.mIsValid && aRhs.mIsValid); \
690 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
691 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
692 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
693 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /)
694 MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %)
696 #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
698 // Implement castToCheckedInt<T>(x), making sure that
699 // - it allows x to be either a CheckedInt<T> or any integer type
700 // that can be casted to T
701 // - if x is already a CheckedInt<T>, we just return a reference to it,
702 // instead of copying it (optimization)
704 namespace detail {
706 template<typename T, typename U>
707 struct CastToCheckedIntImpl
709 typedef CheckedInt<T> ReturnType;
710 static CheckedInt<T> run(U aU) { return aU; }
713 template<typename T>
714 struct CastToCheckedIntImpl<T, CheckedInt<T> >
716 typedef const CheckedInt<T>& ReturnType;
717 static const CheckedInt<T>& run(const CheckedInt<T>& aU) { return aU; }
720 } // namespace detail
722 template<typename T, typename U>
723 inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
724 castToCheckedInt(U aU)
726 static_assert(detail::IsSupported<T>::value &&
727 detail::IsSupported<U>::value,
728 "This type is not supported by CheckedInt");
729 return detail::CastToCheckedIntImpl<T, U>::run(aU);
732 #define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
733 template<typename T> \
734 template<typename U> \
735 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
737 *this = *this OP castToCheckedInt<T>(aRhs); \
738 return *this; \
740 template<typename T> \
741 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const CheckedInt<T>& aRhs) \
743 *this = *this OP aRhs; \
744 return *this; \
746 template<typename T, typename U> \
747 inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) \
749 return aLhs OP castToCheckedInt<T>(aRhs); \
751 template<typename T, typename U> \
752 inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) \
754 return castToCheckedInt<T>(aLhs) OP aRhs; \
757 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
758 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
759 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
760 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
761 MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
763 #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
765 template<typename T, typename U>
766 inline bool
767 operator ==(const CheckedInt<T>& aLhs, U aRhs)
769 return aLhs == castToCheckedInt<T>(aRhs);
772 template<typename T, typename U>
773 inline bool
774 operator ==(U aLhs, const CheckedInt<T>& aRhs)
776 return castToCheckedInt<T>(aLhs) == aRhs;
779 // Convenience typedefs.
780 typedef CheckedInt<int8_t> CheckedInt8;
781 typedef CheckedInt<uint8_t> CheckedUint8;
782 typedef CheckedInt<int16_t> CheckedInt16;
783 typedef CheckedInt<uint16_t> CheckedUint16;
784 typedef CheckedInt<int32_t> CheckedInt32;
785 typedef CheckedInt<uint32_t> CheckedUint32;
786 typedef CheckedInt<int64_t> CheckedInt64;
787 typedef CheckedInt<uint64_t> CheckedUint64;
789 } // namespace mozilla
791 #endif /* mozilla_CheckedInt_h */