CheckedInt.h 23 KB

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