CheckedArithmetic.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. /*
  2. * Copyright (C) 2011 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef CheckedArithmetic_h
  26. #define CheckedArithmetic_h
  27. #include <wtf/Assertions.h>
  28. #include <wtf/EnumClass.h>
  29. #include <wtf/TypeTraits.h>
  30. #include <limits>
  31. #include <stdint.h>
  32. /* Checked<T>
  33. *
  34. * This class provides a mechanism to perform overflow-safe integer arithmetic
  35. * without having to manually ensure that you have all the required bounds checks
  36. * directly in your code.
  37. *
  38. * There are two modes of operation:
  39. * - The default is Checked<T, CrashOnOverflow>, and crashes at the point
  40. * and overflow has occurred.
  41. * - The alternative is Checked<T, RecordOverflow>, which uses an additional
  42. * byte of storage to track whether an overflow has occurred, subsequent
  43. * unchecked operations will crash if an overflow has occured
  44. *
  45. * It is possible to provide a custom overflow handler, in which case you need
  46. * to support these functions:
  47. * - void overflowed();
  48. * This function is called when an operation has produced an overflow.
  49. * - bool hasOverflowed();
  50. * This function must return true if overflowed() has been called on an
  51. * instance and false if it has not.
  52. * - void clearOverflow();
  53. * Used to reset overflow tracking when a value is being overwritten with
  54. * a new value.
  55. *
  56. * Checked<T> works for all integer types, with the following caveats:
  57. * - Mixing signedness of operands is only supported for types narrower than
  58. * 64bits.
  59. * - It does have a performance impact, so tight loops may want to be careful
  60. * when using it.
  61. *
  62. */
  63. namespace WTF {
  64. ENUM_CLASS(CheckedState)
  65. {
  66. DidOverflow,
  67. DidNotOverflow
  68. } ENUM_CLASS_END(CheckedState);
  69. class CrashOnOverflow {
  70. public:
  71. static NO_RETURN_DUE_TO_CRASH void overflowed()
  72. {
  73. CRASH();
  74. }
  75. void clearOverflow() { }
  76. public:
  77. bool hasOverflowed() const { return false; }
  78. };
  79. class RecordOverflow {
  80. protected:
  81. RecordOverflow()
  82. : m_overflowed(false)
  83. {
  84. }
  85. void overflowed()
  86. {
  87. m_overflowed = true;
  88. }
  89. void clearOverflow()
  90. {
  91. m_overflowed = false;
  92. }
  93. public:
  94. bool hasOverflowed() const { return m_overflowed; }
  95. private:
  96. unsigned char m_overflowed;
  97. };
  98. template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
  99. template <typename T> struct RemoveChecked;
  100. template <typename T> struct RemoveChecked<Checked<T> >;
  101. template <typename Target, typename Source, bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker;
  102. template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
  103. static bool inBounds(Source value)
  104. {
  105. // Same signedness so implicit type conversion will always increase precision
  106. // to widest type
  107. return value <= std::numeric_limits<Target>::max();
  108. }
  109. };
  110. template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
  111. static bool inBounds(Source value)
  112. {
  113. // Same signedness so implicit type conversion will always increase precision
  114. // to widest type
  115. return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max();
  116. }
  117. };
  118. template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
  119. static bool inBounds(Source value)
  120. {
  121. // Target is unsigned so any value less than zero is clearly unsafe
  122. if (value < 0)
  123. return false;
  124. // If our (unsigned) Target is the same or greater width we can
  125. // convert value to type Target without losing precision
  126. if (sizeof(Target) >= sizeof(Source))
  127. return static_cast<Target>(value) <= std::numeric_limits<Target>::max();
  128. // The signed Source type has greater precision than the target so
  129. // max(Target) -> Source will widen.
  130. return value <= static_cast<Source>(std::numeric_limits<Target>::max());
  131. }
  132. };
  133. template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
  134. static bool inBounds(Source value)
  135. {
  136. // Signed target with an unsigned source
  137. if (sizeof(Target) <= sizeof(Source))
  138. return value <= static_cast<Source>(std::numeric_limits<Target>::max());
  139. // Target is Wider than Source so we're guaranteed to fit any value in
  140. // unsigned Source
  141. return true;
  142. }
  143. };
  144. template <typename Target, typename Source, bool CanElide = IsSameType<Target, Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider;
  145. template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
  146. static bool inBounds(Source) { return true; }
  147. };
  148. template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
  149. };
  150. template <typename Target, typename Source> static inline bool isInBounds(Source value)
  151. {
  152. return BoundsCheckElider<Target, Source>::inBounds(value);
  153. }
  154. template <typename T> struct RemoveChecked {
  155. typedef T CleanType;
  156. static const CleanType DefaultValue = 0;
  157. };
  158. template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
  159. typedef typename RemoveChecked<T>::CleanType CleanType;
  160. static const CleanType DefaultValue = 0;
  161. };
  162. template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
  163. typedef typename RemoveChecked<T>::CleanType CleanType;
  164. static const CleanType DefaultValue = 0;
  165. };
  166. // The ResultBase and SignednessSelector are used to workaround typeof not being
  167. // available in MSVC
  168. template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
  169. template <typename U, typename V> struct ResultBase<U, V, true, false> {
  170. typedef U ResultType;
  171. };
  172. template <typename U, typename V> struct ResultBase<U, V, false, false> {
  173. typedef V ResultType;
  174. };
  175. template <typename U> struct ResultBase<U, U, false, true> {
  176. typedef U ResultType;
  177. };
  178. template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector;
  179. template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
  180. typedef U ResultType;
  181. };
  182. template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
  183. typedef U ResultType;
  184. };
  185. template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
  186. typedef V ResultType;
  187. };
  188. template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
  189. typedef U ResultType;
  190. };
  191. template <typename U, typename V> struct ResultBase<U, V, false, true> {
  192. typedef typename SignednessSelector<U, V>::ResultType ResultType;
  193. };
  194. template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
  195. };
  196. template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
  197. bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
  198. template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
  199. // LHS and RHS are signed types
  200. // Helper function
  201. static inline bool signsMatch(LHS lhs, RHS rhs)
  202. {
  203. return (lhs ^ rhs) >= 0;
  204. }
  205. static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  206. {
  207. if (signsMatch(lhs, rhs)) {
  208. if (lhs >= 0) {
  209. if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
  210. return false;
  211. } else {
  212. ResultType temp = lhs - std::numeric_limits<ResultType>::min();
  213. if (rhs < -temp)
  214. return false;
  215. }
  216. } // if the signs do not match this operation can't overflow
  217. result = lhs + rhs;
  218. return true;
  219. }
  220. static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  221. {
  222. if (!signsMatch(lhs, rhs)) {
  223. if (lhs >= 0) {
  224. if (lhs > std::numeric_limits<ResultType>::max() + rhs)
  225. return false;
  226. } else {
  227. if (rhs > std::numeric_limits<ResultType>::max() + lhs)
  228. return false;
  229. }
  230. } // if the signs match this operation can't overflow
  231. result = lhs - rhs;
  232. return true;
  233. }
  234. static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  235. {
  236. if (signsMatch(lhs, rhs)) {
  237. if (lhs >= 0) {
  238. if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
  239. return false;
  240. } else {
  241. if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultType>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::min())
  242. return false;
  243. if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
  244. return false;
  245. }
  246. } else {
  247. if (lhs < 0) {
  248. if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
  249. return false;
  250. } else {
  251. if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
  252. return false;
  253. }
  254. }
  255. result = lhs * rhs;
  256. return true;
  257. }
  258. static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
  259. };
  260. template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
  261. // LHS and RHS are unsigned types so bounds checks are nice and easy
  262. static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  263. {
  264. ResultType temp = lhs + rhs;
  265. if (temp < lhs)
  266. return false;
  267. result = temp;
  268. return true;
  269. }
  270. static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  271. {
  272. ResultType temp = lhs - rhs;
  273. if (temp > lhs)
  274. return false;
  275. result = temp;
  276. return true;
  277. }
  278. static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
  279. {
  280. if (!lhs || !rhs) {
  281. result = 0;
  282. return true;
  283. }
  284. if (std::numeric_limits<ResultType>::max() / lhs < rhs)
  285. return false;
  286. result = lhs * rhs;
  287. return true;
  288. }
  289. static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
  290. };
  291. template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
  292. static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
  293. {
  294. int64_t temp = lhs + rhs;
  295. if (temp < std::numeric_limits<ResultType>::min())
  296. return false;
  297. if (temp > std::numeric_limits<ResultType>::max())
  298. return false;
  299. result = static_cast<ResultType>(temp);
  300. return true;
  301. }
  302. static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
  303. {
  304. int64_t temp = lhs - rhs;
  305. if (temp < std::numeric_limits<ResultType>::min())
  306. return false;
  307. if (temp > std::numeric_limits<ResultType>::max())
  308. return false;
  309. result = static_cast<ResultType>(temp);
  310. return true;
  311. }
  312. static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
  313. {
  314. int64_t temp = lhs * rhs;
  315. if (temp < std::numeric_limits<ResultType>::min())
  316. return false;
  317. if (temp > std::numeric_limits<ResultType>::max())
  318. return false;
  319. result = static_cast<ResultType>(temp);
  320. return true;
  321. }
  322. static inline bool equals(int lhs, unsigned rhs)
  323. {
  324. return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
  325. }
  326. };
  327. template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
  328. static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
  329. {
  330. return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
  331. }
  332. static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
  333. {
  334. return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
  335. }
  336. static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
  337. {
  338. return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
  339. }
  340. static inline bool equals(unsigned lhs, int rhs)
  341. {
  342. return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
  343. }
  344. };
  345. template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
  346. {
  347. return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
  348. }
  349. template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
  350. {
  351. return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
  352. }
  353. template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
  354. {
  355. return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
  356. }
  357. template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
  358. {
  359. return ArithmeticOperations<U, V>::equals(lhs, rhs);
  360. }
  361. enum ResultOverflowedTag { ResultOverflowed };
  362. // FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801
  363. static inline bool workAroundClangBug() { return true; }
  364. template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
  365. public:
  366. template <typename _T, class _OverflowHandler> friend class Checked;
  367. Checked()
  368. : m_value(0)
  369. {
  370. }
  371. Checked(ResultOverflowedTag)
  372. : m_value(0)
  373. {
  374. // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
  375. if (workAroundClangBug())
  376. this->overflowed();
  377. }
  378. template <typename U> Checked(U value)
  379. {
  380. if (!isInBounds<T>(value))
  381. this->overflowed();
  382. m_value = static_cast<T>(value);
  383. }
  384. template <typename V> Checked(const Checked<T, V>& rhs)
  385. : m_value(rhs.m_value)
  386. {
  387. if (rhs.hasOverflowed())
  388. this->overflowed();
  389. }
  390. template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
  391. : OverflowHandler(rhs)
  392. {
  393. if (!isInBounds<T>(rhs.m_value))
  394. this->overflowed();
  395. m_value = static_cast<T>(rhs.m_value);
  396. }
  397. template <typename U, typename V> Checked(const Checked<U, V>& rhs)
  398. {
  399. if (rhs.hasOverflowed())
  400. this->overflowed();
  401. if (!isInBounds<T>(rhs.m_value))
  402. this->overflowed();
  403. m_value = static_cast<T>(rhs.m_value);
  404. }
  405. const Checked& operator=(Checked rhs)
  406. {
  407. this->clearOverflow();
  408. if (rhs.hasOverflowed())
  409. this->overflowed();
  410. m_value = static_cast<T>(rhs.m_value);
  411. return *this;
  412. }
  413. template <typename U> const Checked& operator=(U value)
  414. {
  415. return *this = Checked(value);
  416. }
  417. template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
  418. {
  419. return *this = Checked(rhs);
  420. }
  421. // prefix
  422. const Checked& operator++()
  423. {
  424. if (m_value == std::numeric_limits<T>::max())
  425. this->overflowed();
  426. m_value++;
  427. return *this;
  428. }
  429. const Checked& operator--()
  430. {
  431. if (m_value == std::numeric_limits<T>::min())
  432. this->overflowed();
  433. m_value--;
  434. return *this;
  435. }
  436. // postfix operators
  437. const Checked operator++(int)
  438. {
  439. if (m_value == std::numeric_limits<T>::max())
  440. this->overflowed();
  441. return Checked(m_value++);
  442. }
  443. const Checked operator--(int)
  444. {
  445. if (m_value == std::numeric_limits<T>::min())
  446. this->overflowed();
  447. return Checked(m_value--);
  448. }
  449. // Boolean operators
  450. bool operator!() const
  451. {
  452. if (this->hasOverflowed())
  453. CRASH();
  454. return !m_value;
  455. }
  456. typedef void* (Checked::*UnspecifiedBoolType);
  457. operator UnspecifiedBoolType*() const
  458. {
  459. if (this->hasOverflowed())
  460. CRASH();
  461. return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
  462. }
  463. // Value accessors. unsafeGet() will crash if there's been an overflow.
  464. T unsafeGet() const
  465. {
  466. if (this->hasOverflowed())
  467. CRASH();
  468. return m_value;
  469. }
  470. inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
  471. {
  472. value = m_value;
  473. if (this->hasOverflowed())
  474. return CheckedState::DidOverflow;
  475. return CheckedState::DidNotOverflow;
  476. }
  477. // Mutating assignment
  478. template <typename U> const Checked operator+=(U rhs)
  479. {
  480. if (!safeAdd(m_value, rhs, m_value))
  481. this->overflowed();
  482. return *this;
  483. }
  484. template <typename U> const Checked operator-=(U rhs)
  485. {
  486. if (!safeSub(m_value, rhs, m_value))
  487. this->overflowed();
  488. return *this;
  489. }
  490. template <typename U> const Checked operator*=(U rhs)
  491. {
  492. if (!safeMultiply(m_value, rhs, m_value))
  493. this->overflowed();
  494. return *this;
  495. }
  496. const Checked operator*=(double rhs)
  497. {
  498. double result = rhs * m_value;
  499. // Handle +/- infinity and NaN
  500. if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
  501. this->overflowed();
  502. m_value = (T)result;
  503. return *this;
  504. }
  505. const Checked operator*=(float rhs)
  506. {
  507. return *this *= (double)rhs;
  508. }
  509. template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
  510. {
  511. if (rhs.hasOverflowed())
  512. this->overflowed();
  513. return *this += rhs.m_value;
  514. }
  515. template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
  516. {
  517. if (rhs.hasOverflowed())
  518. this->overflowed();
  519. return *this -= rhs.m_value;
  520. }
  521. template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
  522. {
  523. if (rhs.hasOverflowed())
  524. this->overflowed();
  525. return *this *= rhs.m_value;
  526. }
  527. // Equality comparisons
  528. template <typename V> bool operator==(Checked<T, V> rhs)
  529. {
  530. return unsafeGet() == rhs.unsafeGet();
  531. }
  532. template <typename U> bool operator==(U rhs)
  533. {
  534. if (this->hasOverflowed())
  535. this->overflowed();
  536. return safeEquals(m_value, rhs);
  537. }
  538. template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
  539. {
  540. return unsafeGet() == Checked(rhs.unsafeGet());
  541. }
  542. template <typename U> bool operator!=(U rhs)
  543. {
  544. return !(*this == rhs);
  545. }
  546. private:
  547. // Disallow implicit conversion of floating point to integer types
  548. Checked(float);
  549. Checked(double);
  550. void operator=(float);
  551. void operator=(double);
  552. void operator+=(float);
  553. void operator+=(double);
  554. void operator-=(float);
  555. void operator-=(double);
  556. T m_value;
  557. };
  558. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
  559. {
  560. U x = 0;
  561. V y = 0;
  562. bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
  563. typename Result<U, V>::ResultType result = 0;
  564. overflowed |= !safeAdd(x, y, result);
  565. if (overflowed)
  566. return ResultOverflowed;
  567. return result;
  568. }
  569. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
  570. {
  571. U x = 0;
  572. V y = 0;
  573. bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
  574. typename Result<U, V>::ResultType result = 0;
  575. overflowed |= !safeSub(x, y, result);
  576. if (overflowed)
  577. return ResultOverflowed;
  578. return result;
  579. }
  580. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
  581. {
  582. U x = 0;
  583. V y = 0;
  584. bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
  585. typename Result<U, V>::ResultType result = 0;
  586. overflowed |= !safeMultiply(x, y, result);
  587. if (overflowed)
  588. return ResultOverflowed;
  589. return result;
  590. }
  591. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
  592. {
  593. return lhs + Checked<V, OverflowHandler>(rhs);
  594. }
  595. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
  596. {
  597. return lhs - Checked<V, OverflowHandler>(rhs);
  598. }
  599. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
  600. {
  601. return lhs * Checked<V, OverflowHandler>(rhs);
  602. }
  603. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
  604. {
  605. return Checked<U, OverflowHandler>(lhs) + rhs;
  606. }
  607. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
  608. {
  609. return Checked<U, OverflowHandler>(lhs) - rhs;
  610. }
  611. template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
  612. {
  613. return Checked<U, OverflowHandler>(lhs) * rhs;
  614. }
  615. }
  616. using WTF::Checked;
  617. using WTF::CheckedState;
  618. using WTF::RecordOverflow;
  619. #endif