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
26#ifndef CheckedArithmetic_h
27#define CheckedArithmetic_h
28
29#include <wtf/Assertions.h>
30#include <wtf/EnumClass.h>
31#include <wtf/TypeTraits.h>
32
33#include <limits>
34#include <stdint.h>
35
36/* Checked<T>
37 *
38 * This class provides a mechanism to perform overflow-safe integer arithmetic
39 * without having to manually ensure that you have all the required bounds checks
40 * directly in your code.
41 *
42 * There are two modes of operation:
43 * - The default is Checked<T, CrashOnOverflow>, and crashes at the point
44 * and overflow has occurred.
45 * - The alternative is Checked<T, RecordOverflow>, which uses an additional
46 * byte of storage to track whether an overflow has occurred, subsequent
47 * unchecked operations will crash if an overflow has occured
48 *
49 * It is possible to provide a custom overflow handler, in which case you need
50 * to support these functions:
51 * - void overflowed();
52 * This function is called when an operation has produced an overflow.
53 * - bool hasOverflowed();
54 * This function must return true if overflowed() has been called on an
55 * instance and false if it has not.
56 * - void clearOverflow();
57 * Used to reset overflow tracking when a value is being overwritten with
58 * a new value.
59 *
60 * Checked<T> works for all integer types, with the following caveats:
61 * - Mixing signedness of operands is only supported for types narrower than
62 * 64bits.
63 * - It does have a performance impact, so tight loops may want to be careful
64 * when using it.
65 *
66 */
67
68namespace WTF {
69
70ENUM_CLASS(CheckedState)
71{
72 DidOverflow,
73 DidNotOverflow
74} ENUM_CLASS_END(CheckedState);
75
76class CrashOnOverflow {
77public:
78 static NO_RETURN_DUE_TO_CRASH void overflowed()
79 {
80 CRASH();
81 }
82
83 void clearOverflow() { }
84
85public:
86 bool hasOverflowed() const { return false; }
87};
88
89class RecordOverflow {
90protected:
91 RecordOverflow()
92 : m_overflowed(false)
93 {
94 }
95
96 void overflowed()
97 {
98 m_overflowed = true;
99 }
100
101 void clearOverflow()
102 {
103 m_overflowed = false;
104 }
105
106public:
107 bool hasOverflowed() const { return m_overflowed; }
108
109private:
110 unsigned char m_overflowed;
111};
112
113template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
114template <typename T> struct RemoveChecked;
115template <typename T> struct RemoveChecked<Checked<T> >;
116
117template <typename Target, typename Source, bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker;
118template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
119 static bool inBounds(Source value)
120 {
121 // Same signedness so implicit type conversion will always increase precision
122 // to widest type
123 return value <= std::numeric_limits<Target>::max();
124 }
125};
126
127template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
128 static bool inBounds(Source value)
129 {
130 // Same signedness so implicit type conversion will always increase precision
131 // to widest type
132 return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max();
133 }
134};
135
136template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
137 static bool inBounds(Source value)
138 {
139 // Target is unsigned so any value less than zero is clearly unsafe
140 if (value < 0)
141 return false;
142 // If our (unsigned) Target is the same or greater width we can
143 // convert value to type Target without losing precision
144 if (sizeof(Target) >= sizeof(Source))
145 return static_cast<Target>(value) <= std::numeric_limits<Target>::max();
146 // The signed Source type has greater precision than the target so
147 // max(Target) -> Source will widen.
148 return value <= static_cast<Source>(std::numeric_limits<Target>::max());
149 }
150};
151
152template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
153 static bool inBounds(Source value)
154 {
155 // Signed target with an unsigned source
156 if (sizeof(Target) <= sizeof(Source))
157 return value <= static_cast<Source>(std::numeric_limits<Target>::max());
158 // Target is Wider than Source so we're guaranteed to fit any value in
159 // unsigned Source
160 return true;
161 }
162};
163
164template <typename Target, typename Source, bool CanElide = IsSameType<Target, Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider;
165template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
166 static bool inBounds(Source) { return true; }
167};
168template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
169};
170
171template <typename Target, typename Source> static inline bool isInBounds(Source value)
172{
173 return BoundsCheckElider<Target, Source>::inBounds(value);
174}
175
176template <typename T> struct RemoveChecked {
177 typedef T CleanType;
178 static const CleanType DefaultValue = 0;
179};
180
181template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
182 typedef typename RemoveChecked<T>::CleanType CleanType;
183 static const CleanType DefaultValue = 0;
184};
185
186template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
187 typedef typename RemoveChecked<T>::CleanType CleanType;
188 static const CleanType DefaultValue = 0;
189};
190
191// The ResultBase and SignednessSelector are used to workaround typeof not being
192// available in MSVC
193template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
194template <typename U, typename V> struct ResultBase<U, V, true, false> {
195 typedef U ResultType;
196};
197
198template <typename U, typename V> struct ResultBase<U, V, false, false> {
199 typedef V ResultType;
200};
201
202template <typename U> struct ResultBase<U, U, false, true> {
203 typedef U ResultType;
204};
205
206template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector;
207template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
208 typedef U ResultType;
209};
210
211template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
212 typedef U ResultType;
213};
214
215template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
216 typedef V ResultType;
217};
218
219template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
220 typedef U ResultType;
221};
222
223template <typename U, typename V> struct ResultBase<U, V, false, true> {
224 typedef typename SignednessSelector<U, V>::ResultType ResultType;
225};
226
227template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
228};
229
230template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
231 bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
232
233template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
234 // LHS and RHS are signed types
235
236 // Helper function
237 static inline bool signsMatch(LHS lhs, RHS rhs)
238 {
239 return (lhs ^ rhs) >= 0;
240 }
241
242 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
243 {
244 if (signsMatch(lhs, rhs)) {
245 if (lhs >= 0) {
246 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
247 return false;
248 } else {
249 ResultType temp = lhs - std::numeric_limits<ResultType>::min();
250 if (rhs < -temp)
251 return false;
252 }
253 } // if the signs do not match this operation can't overflow
254 result = lhs + rhs;
255 return true;
256 }
257
258 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
259 {
260 if (!signsMatch(lhs, rhs)) {
261 if (lhs >= 0) {
262 if (lhs > std::numeric_limits<ResultType>::max() + rhs)
263 return false;
264 } else {
265 if (rhs > std::numeric_limits<ResultType>::max() + lhs)
266 return false;
267 }
268 } // if the signs match this operation can't overflow
269 result = lhs - rhs;
270 return true;
271 }
272
273 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
274 {
275 if (signsMatch(lhs, rhs)) {
276 if (lhs >= 0) {
277 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
278 return false;
279 } else {
280 if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultType>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::min())
281 return false;
282 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
283 return false;
284 }
285 } else {
286 if (lhs < 0) {
287 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
288 return false;
289 } else {
290 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
291 return false;
292 }
293 }
294 result = lhs * rhs;
295 return true;
296 }
297
298 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
299
300};
301
302template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
303 // LHS and RHS are unsigned types so bounds checks are nice and easy
304 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
305 {
306 ResultType temp = lhs + rhs;
307 if (temp < lhs)
308 return false;
309 result = temp;
310 return true;
311 }
312
313 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
314 {
315 ResultType temp = lhs - rhs;
316 if (temp > lhs)
317 return false;
318 result = temp;
319 return true;
320 }
321
322 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
323 {
324 if (!lhs || !rhs) {
325 result = 0;
326 return true;
327 }
328 if (std::numeric_limits<ResultType>::max() / lhs < rhs)
329 return false;
330 result = lhs * rhs;
331 return true;
332 }
333
334 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
335
336};
337
338template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
339 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
340 {
341 int64_t temp = lhs + rhs;
342 if (temp < std::numeric_limits<ResultType>::min())
343 return false;
344 if (temp > std::numeric_limits<ResultType>::max())
345 return false;
346 result = static_cast<ResultType>(temp);
347 return true;
348 }
349
350 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
351 {
352 int64_t temp = lhs - rhs;
353 if (temp < std::numeric_limits<ResultType>::min())
354 return false;
355 if (temp > std::numeric_limits<ResultType>::max())
356 return false;
357 result = static_cast<ResultType>(temp);
358 return true;
359 }
360
361 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
362 {
363 int64_t temp = lhs * rhs;
364 if (temp < std::numeric_limits<ResultType>::min())
365 return false;
366 if (temp > std::numeric_limits<ResultType>::max())
367 return false;
368 result = static_cast<ResultType>(temp);
369 return true;
370 }
371
372 static inline bool equals(int lhs, unsigned rhs)
373 {
374 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
375 }
376};
377
378template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
379 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
380 {
381 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
382 }
383
384 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
385 {
386 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
387 }
388
389 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
390 {
391 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
392 }
393
394 static inline bool equals(unsigned lhs, int rhs)
395 {
396 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
397 }
398};
399
400template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
401{
402 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
403}
404
405template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
406{
407 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
408}
409
410template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
411{
412 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
413}
414
415template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
416{
417 return ArithmeticOperations<U, V>::equals(lhs, rhs);
418}
419
420enum ResultOverflowedTag { ResultOverflowed };
421
422// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801
423static inline bool workAroundClangBug() { return true; }
424
425template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
426public:
427 template <typename _T, class _OverflowHandler> friend class Checked;
428 Checked()
429 : m_value(0)
430 {
431 }
432
433 Checked(const Checked &) = default;
434
435
436 Checked(ResultOverflowedTag)
437 : m_value(0)
438 {
439 // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
440 if (workAroundClangBug())
441 this->overflowed();
442 }
443
444 template <typename U> Checked(U value)
445 {
446 if (!isInBounds<T>(value))
447 this->overflowed();
448 m_value = static_cast<T>(value);
449 }
450
451 template <typename V> Checked(const Checked<T, V>& rhs)
452 : m_value(rhs.m_value)
453 {
454 if (rhs.hasOverflowed())
455 this->overflowed();
456 }
457
458 template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
459 : OverflowHandler(rhs)
460 {
461 if (!isInBounds<T>(rhs.m_value))
462 this->overflowed();
463 m_value = static_cast<T>(rhs.m_value);
464 }
465
466 template <typename U, typename V> Checked(const Checked<U, V>& rhs)
467 {
468 if (rhs.hasOverflowed())
469 this->overflowed();
470 if (!isInBounds<T>(rhs.m_value))
471 this->overflowed();
472 m_value = static_cast<T>(rhs.m_value);
473 }
474
475 const Checked& operator=(Checked rhs)
476 {
477 this->clearOverflow();
478 if (rhs.hasOverflowed())
479 this->overflowed();
480 m_value = static_cast<T>(rhs.m_value);
481 return *this;
482 }
483
484 template <typename U> const Checked& operator=(U value)
485 {
486 return *this = Checked(value);
487 }
488
489 template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
490 {
491 return *this = Checked(rhs);
492 }
493
494 // prefix
495 const Checked& operator++()
496 {
497 if (m_value == std::numeric_limits<T>::max())
498 this->overflowed();
499 m_value++;
500 return *this;
501 }
502
503 const Checked& operator--()
504 {
505 if (m_value == std::numeric_limits<T>::min())
506 this->overflowed();
507 m_value--;
508 return *this;
509 }
510
511 // postfix operators
512 const Checked operator++(int)
513 {
514 if (m_value == std::numeric_limits<T>::max())
515 this->overflowed();
516 return Checked(m_value++);
517 }
518
519 const Checked operator--(int)
520 {
521 if (m_value == std::numeric_limits<T>::min())
522 this->overflowed();
523 return Checked(m_value--);
524 }
525
526 // Boolean operators
527 bool operator!() const
528 {
529 if (this->hasOverflowed())
530 CRASH();
531 return !m_value;
532 }
533
534 typedef void* (Checked::*UnspecifiedBoolType);
535 operator UnspecifiedBoolType*() const
536 {
537 if (this->hasOverflowed())
538 CRASH();
539 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
540 }
541
542 // Value accessors. unsafeGet() will crash if there's been an overflow.
543 T unsafeGet() const
544 {
545 if (this->hasOverflowed())
546 CRASH();
547 return m_value;
548 }
549
550 inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
551 {
552 value = m_value;
553 if (this->hasOverflowed())
554 return CheckedState::DidOverflow;
555 return CheckedState::DidNotOverflow;
556 }
557
558 // Mutating assignment
559 template <typename U> const Checked operator+=(U rhs)
560 {
561 if (!safeAdd(m_value, rhs, m_value))
562 this->overflowed();
563 return *this;
564 }
565
566 template <typename U> const Checked operator-=(U rhs)
567 {
568 if (!safeSub(m_value, rhs, m_value))
569 this->overflowed();
570 return *this;
571 }
572
573 template <typename U> const Checked operator*=(U rhs)
574 {
575 if (!safeMultiply(m_value, rhs, m_value))
576 this->overflowed();
577 return *this;
578 }
579
580 const Checked operator*=(double rhs)
581 {
582 double result = rhs * m_value;
583 // Handle +/- infinity and NaN
584 if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
585 this->overflowed();
586 m_value = (T)result;
587 return *this;
588 }
589
590 const Checked operator*=(float rhs)
591 {
592 return *this *= (double)rhs;
593 }
594
595 template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
596 {
597 if (rhs.hasOverflowed())
598 this->overflowed();
599 return *this += rhs.m_value;
600 }
601
602 template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
603 {
604 if (rhs.hasOverflowed())
605 this->overflowed();
606 return *this -= rhs.m_value;
607 }
608
609 template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
610 {
611 if (rhs.hasOverflowed())
612 this->overflowed();
613 return *this *= rhs.m_value;
614 }
615
616 // Equality comparisons
617 template <typename V> bool operator==(Checked<T, V> rhs)
618 {
619 return unsafeGet() == rhs.unsafeGet();
620 }
621
622 template <typename U> bool operator==(U rhs)
623 {
624 if (this->hasOverflowed())
625 this->overflowed();
626 return safeEquals(m_value, rhs);
627 }
628
629 template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
630 {
631 return unsafeGet() == Checked(rhs.unsafeGet());
632 }
633
634 template <typename U> bool operator!=(U rhs)
635 {
636 return !(*this == rhs);
637 }
638
639private:
640 // Disallow implicit conversion of floating point to integer types
641 Checked(float);
642 Checked(double);
643 void operator=(float);
644 void operator=(double);
645 void operator+=(float);
646 void operator+=(double);
647 void operator-=(float);
648 void operator-=(double);
649 T m_value;
650};
651
652template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
653{
654 U x = 0;
655 V y = 0;
656 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
657 typename Result<U, V>::ResultType result = 0;
658 overflowed |= !safeAdd(x, y, result);
659 if (overflowed)
660 return ResultOverflowed;
661 return result;
662}
663
664template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
665{
666 U x = 0;
667 V y = 0;
668 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
669 typename Result<U, V>::ResultType result = 0;
670 overflowed |= !safeSub(x, y, result);
671 if (overflowed)
672 return ResultOverflowed;
673 return result;
674}
675
676template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
677{
678 U x = 0;
679 V y = 0;
680 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
681 typename Result<U, V>::ResultType result = 0;
682 overflowed |= !safeMultiply(x, y, result);
683 if (overflowed)
684 return ResultOverflowed;
685 return result;
686}
687
688template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
689{
690 return lhs + Checked<V, OverflowHandler>(rhs);
691}
692
693template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
694{
695 return lhs - Checked<V, OverflowHandler>(rhs);
696}
697
698template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
699{
700 return lhs * Checked<V, OverflowHandler>(rhs);
701}
702
703template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
704{
705 return Checked<U, OverflowHandler>(lhs) + rhs;
706}
707
708template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
709{
710 return Checked<U, OverflowHandler>(lhs) - rhs;
711}
712
713template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
714{
715 return Checked<U, OverflowHandler>(lhs) * rhs;
716}
717
718}
719
720using WTF::Checked;
721using WTF::CheckedState;
722using WTF::RecordOverflow;
723
724#endif
725

source code of qtdeclarative/src/3rdparty/masm/wtf/CheckedArithmetic.h