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 {
77protected:
78    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
422template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
423public:
424    template <typename _T, class _OverflowHandler> friend class Checked;
425    Checked()
426        : m_value(0)
427    {
428    }
429
430    Checked(ResultOverflowedTag)
431        : m_value(0)
432    {
433        this->overflowed();
434    }
435
436    template <typename U> Checked(U value)
437    {
438        if (!isInBounds<T>(value))
439            this->overflowed();
440        m_value = static_cast<T>(value);
441    }
442
443    template <typename V> Checked(const Checked<T, V>& rhs)
444        : m_value(rhs.m_value)
445    {
446        if (rhs.hasOverflowed())
447            this->overflowed();
448    }
449
450    template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
451        : OverflowHandler(rhs)
452    {
453        if (!isInBounds<T>(rhs.m_value))
454            this->overflowed();
455        m_value = static_cast<T>(rhs.m_value);
456    }
457
458    template <typename U, typename V> Checked(const Checked<U, V>& rhs)
459    {
460        if (rhs.hasOverflowed())
461            this->overflowed();
462        if (!isInBounds<T>(rhs.m_value))
463            this->overflowed();
464        m_value = static_cast<T>(rhs.m_value);
465    }
466
467    const Checked& operator=(Checked rhs)
468    {
469        this->clearOverflow();
470        if (rhs.hasOverflowed())
471            this->overflowed();
472        m_value = static_cast<T>(rhs.m_value);
473        return *this;
474    }
475
476    template <typename U> const Checked& operator=(U value)
477    {
478        return *this = Checked(value);
479    }
480
481    template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
482    {
483        return *this = Checked(rhs);
484    }
485
486    // prefix
487    const Checked& operator++()
488    {
489        if (m_value == std::numeric_limits<T>::max())
490            this->overflowed();
491        m_value++;
492        return *this;
493    }
494
495    const Checked& operator--()
496    {
497        if (m_value == std::numeric_limits<T>::min())
498            this->overflowed();
499        m_value--;
500        return *this;
501    }
502
503    // postfix operators
504    const Checked operator++(int)
505    {
506        if (m_value == std::numeric_limits<T>::max())
507            this->overflowed();
508        return Checked(m_value++);
509    }
510
511    const Checked operator--(int)
512    {
513        if (m_value == std::numeric_limits<T>::min())
514            this->overflowed();
515        return Checked(m_value--);
516    }
517
518    // Boolean operators
519    bool operator!() const
520    {
521        if (this->hasOverflowed())
522            CRASH();
523        return !m_value;
524    }
525
526    typedef void* (Checked::*UnspecifiedBoolType);
527    operator UnspecifiedBoolType*() const
528    {
529        if (this->hasOverflowed())
530            CRASH();
531        return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
532    }
533
534    // Value accessors. unsafeGet() will crash if there's been an overflow.
535    T unsafeGet() const
536    {
537        if (this->hasOverflowed())
538            CRASH();
539        return m_value;
540    }
541
542    inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
543    {
544        value = m_value;
545        if (this->hasOverflowed())
546            return CheckedState::DidOverflow;
547        return CheckedState::DidNotOverflow;
548    }
549
550    // Mutating assignment
551    template <typename U> const Checked operator+=(U rhs)
552    {
553        if (!safeAdd(m_value, rhs, m_value))
554            this->overflowed();
555        return *this;
556    }
557
558    template <typename U> const Checked operator-=(U rhs)
559    {
560        if (!safeSub(m_value, rhs, m_value))
561            this->overflowed();
562        return *this;
563    }
564
565    template <typename U> const Checked operator*=(U rhs)
566    {
567        if (!safeMultiply(m_value, rhs, m_value))
568            this->overflowed();
569        return *this;
570    }
571
572    const Checked operator*=(double rhs)
573    {
574        double result = rhs * m_value;
575        // Handle +/- infinity and NaN
576        if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
577            this->overflowed();
578        m_value = (T)result;
579        return *this;
580    }
581
582    const Checked operator*=(float rhs)
583    {
584        return *this *= (double)rhs;
585    }
586
587    template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
588    {
589        if (rhs.hasOverflowed())
590            this->overflowed();
591        return *this += rhs.m_value;
592    }
593
594    template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
595    {
596        if (rhs.hasOverflowed())
597            this->overflowed();
598        return *this -= rhs.m_value;
599    }
600
601    template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
602    {
603        if (rhs.hasOverflowed())
604            this->overflowed();
605        return *this *= rhs.m_value;
606    }
607
608    // Equality comparisons
609    template <typename V> bool operator==(Checked<T, V> rhs)
610    {
611        return unsafeGet() == rhs.unsafeGet();
612    }
613
614    template <typename U> bool operator==(U rhs)
615    {
616        if (this->hasOverflowed())
617            this->overflowed();
618        return safeEquals(m_value, rhs);
619    }
620
621    template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
622    {
623        return unsafeGet() == Checked(rhs.unsafeGet());
624    }
625
626    template <typename U> bool operator!=(U rhs)
627    {
628        return !(*this == rhs);
629    }
630
631private:
632    // Disallow implicit conversion of floating point to integer types
633    Checked(float);
634    Checked(double);
635    void operator=(float);
636    void operator=(double);
637    void operator+=(float);
638    void operator+=(double);
639    void operator-=(float);
640    void operator-=(double);
641    T m_value;
642};
643
644template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
645{
646    U x = 0;
647    V y = 0;
648    bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
649    typename Result<U, V>::ResultType result = 0;
650    overflowed |= !safeAdd(x, y, result);
651    if (overflowed)
652        return ResultOverflowed;
653    return result;
654}
655
656template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
657{
658    U x = 0;
659    V y = 0;
660    bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
661    typename Result<U, V>::ResultType result = 0;
662    overflowed |= !safeSub(x, y, result);
663    if (overflowed)
664        return ResultOverflowed;
665    return result;
666}
667
668template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
669{
670    U x = 0;
671    V y = 0;
672    bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
673    typename Result<U, V>::ResultType result = 0;
674    overflowed |= !safeMultiply(x, y, result);
675    if (overflowed)
676        return ResultOverflowed;
677    return result;
678}
679
680template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
681{
682    return lhs + Checked<V, OverflowHandler>(rhs);
683}
684
685template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
686{
687    return lhs - Checked<V, OverflowHandler>(rhs);
688}
689
690template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
691{
692    return lhs * Checked<V, OverflowHandler>(rhs);
693}
694
695template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
696{
697    return Checked<U, OverflowHandler>(lhs) + rhs;
698}
699
700template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
701{
702    return Checked<U, OverflowHandler>(lhs) - rhs;
703}
704
705template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
706{
707    return Checked<U, OverflowHandler>(lhs) * rhs;
708}
709
710}
711
712using WTF::Checked;
713using WTF::CheckedState;
714using WTF::RecordOverflow;
715
716#endif
717