CheckedInt.h 23 KB

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