js/src/yarr/CheckedArithmetic.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/yarr/CheckedArithmetic.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,715 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + *
     1.7 + * Copyright (C) 2011 Apple Inc. All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions
    1.11 + * are met:
    1.12 + * 1. Redistributions of source code must retain the above copyright
    1.13 + *    notice, this list of conditions and the following disclaimer.
    1.14 + * 2. Redistributions in binary form must reproduce the above copyright
    1.15 + *    notice, this list of conditions and the following disclaimer in the
    1.16 + *    documentation and/or other materials provided with the distribution.
    1.17 + *
    1.18 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
    1.19 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    1.21 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
    1.22 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    1.23 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    1.24 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    1.25 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
    1.26 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.27 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.28 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.29 + */
    1.30 +
    1.31 +#ifndef yarr_CheckedArithmetic_h
    1.32 +#define yarr_CheckedArithmetic_h
    1.33 +
    1.34 +#include "assembler/wtf/Assertions.h"
    1.35 +
    1.36 +#include <limits>
    1.37 +#include <stdint.h>
    1.38 +#include "mozilla/TypeTraits.h"
    1.39 +
    1.40 +#ifdef _MSC_VER
    1.41 +# undef min
    1.42 +# undef max
    1.43 +#endif
    1.44 +
    1.45 +/* Checked<T>
    1.46 + *
    1.47 + * This class provides a mechanism to perform overflow-safe integer arithmetic
    1.48 + * without having to manually ensure that you have all the required bounds checks
    1.49 + * directly in your code.
    1.50 + *
    1.51 + * There are two modes of operation:
    1.52 + *  - The default is Checked<T, CrashOnOverflow>, and crashes at the point
    1.53 + *    and overflow has occurred.
    1.54 + *  - The alternative is Checked<T, RecordOverflow>, which uses an additional
    1.55 + *    byte of storage to track whether an overflow has occurred, subsequent
    1.56 + *    unchecked operations will crash if an overflow has occured
    1.57 + *
    1.58 + * It is possible to provide a custom overflow handler, in which case you need
    1.59 + * to support these functions:
    1.60 + *  - void overflowed();
    1.61 + *    This function is called when an operation has produced an overflow.
    1.62 + *  - bool hasOverflowed();
    1.63 + *    This function must return true if overflowed() has been called on an
    1.64 + *    instance and false if it has not.
    1.65 + *  - void clearOverflow();
    1.66 + *    Used to reset overflow tracking when a value is being overwritten with
    1.67 + *    a new value.
    1.68 + *
    1.69 + * Checked<T> works for all integer types, with the following caveats:
    1.70 + *  - Mixing signedness of operands is only supported for types narrower than
    1.71 + *    64bits.
    1.72 + *  - It does have a performance impact, so tight loops may want to be careful
    1.73 + *    when using it.
    1.74 + *
    1.75 + */
    1.76 +
    1.77 +namespace WTF {
    1.78 +
    1.79 +class CrashOnOverflow {
    1.80 +protected:
    1.81 +    void overflowed()
    1.82 +    {
    1.83 +        CRASH();
    1.84 +    }
    1.85 +
    1.86 +    void clearOverflow() { }
    1.87 +
    1.88 +public:
    1.89 +    bool hasOverflowed() const { return false; }
    1.90 +};
    1.91 +
    1.92 +class RecordOverflow {
    1.93 +protected:
    1.94 +    RecordOverflow()
    1.95 +        : m_overflowed(false)
    1.96 +    {
    1.97 +    }
    1.98 +
    1.99 +    void overflowed()
   1.100 +    {
   1.101 +        m_overflowed = true;
   1.102 +    }
   1.103 +
   1.104 +    void clearOverflow()
   1.105 +    {
   1.106 +        m_overflowed = false;
   1.107 +    }
   1.108 +
   1.109 +public:
   1.110 +    bool hasOverflowed() const { return m_overflowed; }
   1.111 +
   1.112 +private:
   1.113 +    unsigned char m_overflowed;
   1.114 +};
   1.115 +
   1.116 +template <typename T, class OverflowHandler = RecordOverflow> class Checked;
   1.117 +template <typename T> struct RemoveChecked;
   1.118 +template <typename T> struct RemoveChecked<Checked<T> >;
   1.119 +
   1.120 +template <typename Target, typename Source, bool targetSigned = ::std::numeric_limits<Target>::is_signed, bool sourceSigned = ::std::numeric_limits<Source>::is_signed> struct BoundsChecker;
   1.121 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
   1.122 +    static bool inBounds(Source value)
   1.123 +    {
   1.124 +        // Same signedness so implicit type conversion will always increase precision
   1.125 +        // to widest type
   1.126 +        return value <= ::std::numeric_limits<Target>::max();
   1.127 +    }
   1.128 +};
   1.129 +
   1.130 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
   1.131 +    static bool inBounds(Source value)
   1.132 +    {
   1.133 +        // Same signedness so implicit type conversion will always increase precision
   1.134 +        // to widest type
   1.135 +        return ::std::numeric_limits<Target>::min() <= value && value <= ::std::numeric_limits<Target>::max();
   1.136 +    }
   1.137 +};
   1.138 +
   1.139 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
   1.140 +    static bool inBounds(Source value)
   1.141 +    {
   1.142 +        // Target is unsigned so any value less than zero is clearly unsafe
   1.143 +        if (value < 0)
   1.144 +            return false;
   1.145 +        // If our (unsigned) Target is the same or greater width we can
   1.146 +        // convert value to type Target without losing precision
   1.147 +        if (sizeof(Target) >= sizeof(Source))
   1.148 +            return static_cast<Target>(value) <= ::std::numeric_limits<Target>::max();
   1.149 +        // The signed Source type has greater precision than the target so
   1.150 +        // max(Target) -> Source will widen.
   1.151 +        return value <= static_cast<Source>(::std::numeric_limits<Target>::max());
   1.152 +    }
   1.153 +};
   1.154 +
   1.155 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
   1.156 +    static bool inBounds(Source value)
   1.157 +    {
   1.158 +        // Signed target with an unsigned source
   1.159 +        if (sizeof(Target) <= sizeof(Source))
   1.160 +            return value <= static_cast<Source>(::std::numeric_limits<Target>::max());
   1.161 +        // Target is Wider than Source so we're guaranteed to fit any value in
   1.162 +        // unsigned Source
   1.163 +        return true;
   1.164 +    }
   1.165 +};
   1.166 +
   1.167 +template <typename Target, typename Source, bool SameType = mozilla::IsSame<Target, Source>::value> struct BoundsCheckElider;
   1.168 +template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
   1.169 +    static bool inBounds(Source) { return true; }
   1.170 +};
   1.171 +template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
   1.172 +};
   1.173 +
   1.174 +template <typename Target, typename Source> static inline bool isInBounds(Source value)
   1.175 +{
   1.176 +    return BoundsCheckElider<Target, Source>::inBounds(value);
   1.177 +}
   1.178 +
   1.179 +template <typename T> struct RemoveChecked {
   1.180 +    typedef T CleanType;
   1.181 +    static const CleanType DefaultValue = 0;
   1.182 +};
   1.183 +
   1.184 +template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
   1.185 +    typedef typename RemoveChecked<T>::CleanType CleanType;
   1.186 +    static const CleanType DefaultValue = 0;
   1.187 +};
   1.188 +
   1.189 +template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
   1.190 +    typedef typename RemoveChecked<T>::CleanType CleanType;
   1.191 +    static const CleanType DefaultValue = 0;
   1.192 +};
   1.193 +
   1.194 +// The ResultBase and SignednessSelector are used to workaround typeof not being
   1.195 +// available in MSVC
   1.196 +template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
   1.197 +template <typename U, typename V> struct ResultBase<U, V, true, false> {
   1.198 +    typedef U ResultType;
   1.199 +};
   1.200 +
   1.201 +template <typename U, typename V> struct ResultBase<U, V, false, false> {
   1.202 +    typedef V ResultType;
   1.203 +};
   1.204 +
   1.205 +template <typename U> struct ResultBase<U, U, false, true> {
   1.206 +    typedef U ResultType;
   1.207 +};
   1.208 +
   1.209 +template <typename U, typename V, bool uIsSigned = ::std::numeric_limits<U>::is_signed, bool vIsSigned = ::std::numeric_limits<V>::is_signed> struct SignednessSelector;
   1.210 +template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
   1.211 +    typedef U ResultType;
   1.212 +};
   1.213 +
   1.214 +template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
   1.215 +    typedef U ResultType;
   1.216 +};
   1.217 +
   1.218 +template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
   1.219 +    typedef V ResultType;
   1.220 +};
   1.221 +
   1.222 +template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
   1.223 +    typedef U ResultType;
   1.224 +};
   1.225 +
   1.226 +template <typename U, typename V> struct ResultBase<U, V, false, true> {
   1.227 +    typedef typename SignednessSelector<U, V>::ResultType ResultType;
   1.228 +};
   1.229 +
   1.230 +template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
   1.231 +};
   1.232 +
   1.233 +template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
   1.234 +    bool lhsSigned = ::std::numeric_limits<LHS>::is_signed, bool rhsSigned = ::std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
   1.235 +
   1.236 +template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
   1.237 +    // LHS and RHS are signed types
   1.238 +
   1.239 +    // Helper function
   1.240 +    static inline bool signsMatch(LHS lhs, RHS rhs)
   1.241 +    {
   1.242 +        return (lhs ^ rhs) >= 0;
   1.243 +    }
   1.244 +
   1.245 +    static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.246 +    {
   1.247 +        if (signsMatch(lhs, rhs)) {
   1.248 +            if (lhs >= 0) {
   1.249 +                if ((::std::numeric_limits<ResultType>::max() - rhs) < lhs)
   1.250 +                    return false;
   1.251 +            } else {
   1.252 +                ResultType temp = lhs - ::std::numeric_limits<ResultType>::min();
   1.253 +                if (rhs < -temp)
   1.254 +                    return false;
   1.255 +            }
   1.256 +        } // if the signs do not match this operation can't overflow
   1.257 +        result = lhs + rhs;
   1.258 +        return true;
   1.259 +    }
   1.260 +
   1.261 +    static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.262 +    {
   1.263 +        if (!signsMatch(lhs, rhs)) {
   1.264 +            if (lhs >= 0) {
   1.265 +                if (lhs > ::std::numeric_limits<ResultType>::max() + rhs)
   1.266 +                    return false;
   1.267 +            } else {
   1.268 +                if (rhs > ::std::numeric_limits<ResultType>::max() + lhs)
   1.269 +                    return false;
   1.270 +            }
   1.271 +        } // if the signs match this operation can't overflow
   1.272 +        result = lhs - rhs;
   1.273 +        return true;
   1.274 +    }
   1.275 +
   1.276 +    static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.277 +    {
   1.278 +        if (signsMatch(lhs, rhs)) {
   1.279 +            if (lhs >= 0) {
   1.280 +                if (lhs && (::std::numeric_limits<ResultType>::max() / lhs) < rhs)
   1.281 +                    return false;
   1.282 +            } else {
   1.283 +                if (lhs == ::std::numeric_limits<ResultType>::min() || rhs == ::std::numeric_limits<ResultType>::min())
   1.284 +                    return false;
   1.285 +                if ((::std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
   1.286 +                    return false;
   1.287 +            }
   1.288 +        } else {
   1.289 +            if (lhs < 0) {
   1.290 +                if (rhs && lhs < (::std::numeric_limits<ResultType>::min() / rhs))
   1.291 +                    return false;
   1.292 +            } else {
   1.293 +                if (lhs && rhs < (::std::numeric_limits<ResultType>::min() / lhs))
   1.294 +                    return false;
   1.295 +            }
   1.296 +        }
   1.297 +        result = lhs * rhs;
   1.298 +        return true;
   1.299 +    }
   1.300 +
   1.301 +    static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
   1.302 +
   1.303 +};
   1.304 +
   1.305 +template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
   1.306 +    // LHS and RHS are unsigned types so bounds checks are nice and easy
   1.307 +    static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.308 +    {
   1.309 +        ResultType temp = lhs + rhs;
   1.310 +        if (temp < lhs)
   1.311 +            return false;
   1.312 +        result = temp;
   1.313 +        return true;
   1.314 +    }
   1.315 +
   1.316 +    static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.317 +    {
   1.318 +        ResultType temp = lhs - rhs;
   1.319 +        if (temp > lhs)
   1.320 +            return false;
   1.321 +        result = temp;
   1.322 +        return true;
   1.323 +    }
   1.324 +
   1.325 +    static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
   1.326 +    {
   1.327 +        ResultType temp = lhs * rhs;
   1.328 +        if (temp < lhs)
   1.329 +            return false;
   1.330 +        result = temp;
   1.331 +        return true;
   1.332 +    }
   1.333 +
   1.334 +    static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
   1.335 +
   1.336 +};
   1.337 +
   1.338 +template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
   1.339 +    static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
   1.340 +    {
   1.341 +        int64_t temp = lhs + rhs;
   1.342 +        if (temp < ::std::numeric_limits<ResultType>::min())
   1.343 +            return false;
   1.344 +        if (temp > ::std::numeric_limits<ResultType>::max())
   1.345 +            return false;
   1.346 +        result = static_cast<ResultType>(temp);
   1.347 +        return true;
   1.348 +    }
   1.349 +
   1.350 +    static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
   1.351 +    {
   1.352 +        int64_t temp = lhs - rhs;
   1.353 +        if (temp < ::std::numeric_limits<ResultType>::min())
   1.354 +            return false;
   1.355 +        if (temp > ::std::numeric_limits<ResultType>::max())
   1.356 +            return false;
   1.357 +        result = static_cast<ResultType>(temp);
   1.358 +        return true;
   1.359 +    }
   1.360 +
   1.361 +    static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
   1.362 +    {
   1.363 +        int64_t temp = lhs * rhs;
   1.364 +        if (temp < ::std::numeric_limits<ResultType>::min())
   1.365 +            return false;
   1.366 +        if (temp > ::std::numeric_limits<ResultType>::max())
   1.367 +            return false;
   1.368 +        result = static_cast<ResultType>(temp);
   1.369 +        return true;
   1.370 +    }
   1.371 +
   1.372 +    static inline bool equals(int lhs, unsigned rhs)
   1.373 +    {
   1.374 +        return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
   1.375 +    }
   1.376 +};
   1.377 +
   1.378 +template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
   1.379 +    static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
   1.380 +    {
   1.381 +        return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
   1.382 +    }
   1.383 +
   1.384 +    static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
   1.385 +    {
   1.386 +        return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
   1.387 +    }
   1.388 +
   1.389 +    static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
   1.390 +    {
   1.391 +        return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
   1.392 +    }
   1.393 +
   1.394 +    static inline bool equals(unsigned lhs, int rhs)
   1.395 +    {
   1.396 +        return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
   1.397 +    }
   1.398 +};
   1.399 +
   1.400 +template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
   1.401 +{
   1.402 +    return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
   1.403 +}
   1.404 +
   1.405 +template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
   1.406 +{
   1.407 +    return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
   1.408 +}
   1.409 +
   1.410 +template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
   1.411 +{
   1.412 +    return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
   1.413 +}
   1.414 +
   1.415 +template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
   1.416 +{
   1.417 +    return ArithmeticOperations<U, V>::equals(lhs, rhs);
   1.418 +}
   1.419 +
   1.420 +enum ResultOverflowedTag { ResultOverflowed };
   1.421 +
   1.422 +// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801
   1.423 +static inline bool workAroundClangBug() { return true; }
   1.424 +
   1.425 +template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
   1.426 +public:
   1.427 +    template <typename _T, class _OverflowHandler> friend class Checked;
   1.428 +    Checked()
   1.429 +        : m_value(0)
   1.430 +    {
   1.431 +    }
   1.432 +
   1.433 +    Checked(ResultOverflowedTag)
   1.434 +        : m_value(0)
   1.435 +    {
   1.436 +        // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
   1.437 +        if (workAroundClangBug())
   1.438 +            this->overflowed();
   1.439 +    }
   1.440 +
   1.441 +    template <typename U> Checked(U value)
   1.442 +    {
   1.443 +        if (!isInBounds<T>(value))
   1.444 +            this->overflowed();
   1.445 +        m_value = static_cast<T>(value);
   1.446 +    }
   1.447 +
   1.448 +    template <typename V> Checked(const Checked<T, V>& rhs)
   1.449 +        : m_value(rhs.m_value)
   1.450 +    {
   1.451 +        if (rhs.hasOverflowed())
   1.452 +            this->overflowed();
   1.453 +    }
   1.454 +
   1.455 +    template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
   1.456 +        : OverflowHandler(rhs)
   1.457 +    {
   1.458 +        if (!isInBounds<T>(rhs.m_value))
   1.459 +            this->overflowed();
   1.460 +        m_value = static_cast<T>(rhs.m_value);
   1.461 +    }
   1.462 +
   1.463 +    template <typename U, typename V> Checked(const Checked<U, V>& rhs)
   1.464 +    {
   1.465 +        if (rhs.hasOverflowed())
   1.466 +            this->overflowed();
   1.467 +        if (!isInBounds<T>(rhs.m_value))
   1.468 +            this->overflowed();
   1.469 +        m_value = static_cast<T>(rhs.m_value);
   1.470 +    }
   1.471 +
   1.472 +    const Checked& operator=(Checked rhs)
   1.473 +    {
   1.474 +        this->clearOverflow();
   1.475 +        if (rhs.hasOverflowed())
   1.476 +            this->overflowed();
   1.477 +        m_value = static_cast<T>(rhs.m_value);
   1.478 +        return *this;
   1.479 +    }
   1.480 +
   1.481 +    template <typename U> const Checked& operator=(U value)
   1.482 +    {
   1.483 +        return *this = Checked(value);
   1.484 +    }
   1.485 +
   1.486 +    template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
   1.487 +    {
   1.488 +        return *this = Checked(rhs);
   1.489 +    }
   1.490 +
   1.491 +    // prefix
   1.492 +    const Checked& operator++()
   1.493 +    {
   1.494 +        if (m_value == ::std::numeric_limits<T>::max())
   1.495 +            this->overflowed();
   1.496 +        m_value++;
   1.497 +        return *this;
   1.498 +    }
   1.499 +
   1.500 +    const Checked& operator--()
   1.501 +    {
   1.502 +        if (m_value == ::std::numeric_limits<T>::min())
   1.503 +            this->overflowed();
   1.504 +        m_value--;
   1.505 +        return *this;
   1.506 +    }
   1.507 +
   1.508 +    // postfix operators
   1.509 +    const Checked operator++(int)
   1.510 +    {
   1.511 +        if (m_value == ::std::numeric_limits<T>::max())
   1.512 +            this->overflowed();
   1.513 +        return Checked(m_value++);
   1.514 +    }
   1.515 +
   1.516 +    const Checked operator--(int)
   1.517 +    {
   1.518 +        if (m_value == ::std::numeric_limits<T>::min())
   1.519 +            this->overflowed();
   1.520 +        return Checked(m_value--);
   1.521 +    }
   1.522 +
   1.523 +    // Boolean operators
   1.524 +    bool operator!() const
   1.525 +    {
   1.526 +        if (this->hasOverflowed())
   1.527 +            CRASH();
   1.528 +        return !m_value;
   1.529 +    }
   1.530 +
   1.531 +    typedef void* (Checked::*UnspecifiedBoolType);
   1.532 +    operator UnspecifiedBoolType*() const
   1.533 +    {
   1.534 +        if (this->hasOverflowed())
   1.535 +            CRASH();
   1.536 +        return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
   1.537 +    }
   1.538 +
   1.539 +    // Value accessors. unsafeGet() will crash if there's been an overflow.
   1.540 +    T unsafeGet() const
   1.541 +    {
   1.542 +        if (this->hasOverflowed())
   1.543 +            CRASH();
   1.544 +        return m_value;
   1.545 +    }
   1.546 +
   1.547 +    bool safeGet(T& value) const WARN_UNUSED_RETURN
   1.548 +    {
   1.549 +        value = m_value;
   1.550 +        return this->hasOverflowed();
   1.551 +    }
   1.552 +
   1.553 +    // Mutating assignment
   1.554 +    template <typename U> const Checked operator+=(U rhs)
   1.555 +    {
   1.556 +        if (!safeAdd(m_value, rhs, m_value))
   1.557 +            this->overflowed();
   1.558 +        return *this;
   1.559 +    }
   1.560 +
   1.561 +    template <typename U> const Checked operator-=(U rhs)
   1.562 +    {
   1.563 +        if (!safeSub(m_value, rhs, m_value))
   1.564 +            this->overflowed();
   1.565 +        return *this;
   1.566 +    }
   1.567 +
   1.568 +    template <typename U> const Checked operator*=(U rhs)
   1.569 +    {
   1.570 +        if (!safeMultiply(m_value, rhs, m_value))
   1.571 +            this->overflowed();
   1.572 +        return *this;
   1.573 +    }
   1.574 +
   1.575 +    const Checked operator*=(double rhs)
   1.576 +    {
   1.577 +        double result = rhs * m_value;
   1.578 +        // Handle +/- infinity and NaN
   1.579 +        if (!(::std::numeric_limits<T>::min() <= result && ::std::numeric_limits<T>::max() >= result))
   1.580 +            this->overflowed();
   1.581 +        m_value = (T)result;
   1.582 +        return *this;
   1.583 +    }
   1.584 +
   1.585 +    const Checked operator*=(float rhs)
   1.586 +    {
   1.587 +        return *this *= (double)rhs;
   1.588 +    }
   1.589 +
   1.590 +    template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
   1.591 +    {
   1.592 +        if (rhs.hasOverflowed())
   1.593 +            this->overflowed();
   1.594 +        return *this += rhs.m_value;
   1.595 +    }
   1.596 +
   1.597 +    template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
   1.598 +    {
   1.599 +        if (rhs.hasOverflowed())
   1.600 +            this->overflowed();
   1.601 +        return *this -= rhs.m_value;
   1.602 +    }
   1.603 +
   1.604 +    template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
   1.605 +    {
   1.606 +        if (rhs.hasOverflowed())
   1.607 +            this->overflowed();
   1.608 +        return *this *= rhs.m_value;
   1.609 +    }
   1.610 +
   1.611 +    // Equality comparisons
   1.612 +    template <typename V> bool operator==(Checked<T, V> rhs)
   1.613 +    {
   1.614 +        return unsafeGet() == rhs.unsafeGet();
   1.615 +    }
   1.616 +
   1.617 +    template <typename U> bool operator==(U rhs)
   1.618 +    {
   1.619 +        if (this->hasOverflowed())
   1.620 +            this->overflowed();
   1.621 +        return safeEquals(m_value, rhs);
   1.622 +    }
   1.623 +
   1.624 +    template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
   1.625 +    {
   1.626 +        return unsafeGet() == Checked(rhs.unsafeGet());
   1.627 +    }
   1.628 +
   1.629 +    template <typename U> bool operator!=(U rhs)
   1.630 +    {
   1.631 +        return !(*this == rhs);
   1.632 +    }
   1.633 +
   1.634 +private:
   1.635 +    // Disallow implicit conversion of floating point to integer types
   1.636 +    Checked(float);
   1.637 +    Checked(double);
   1.638 +    void operator=(float);
   1.639 +    void operator=(double);
   1.640 +    void operator+=(float);
   1.641 +    void operator+=(double);
   1.642 +    void operator-=(float);
   1.643 +    void operator-=(double);
   1.644 +    T m_value;
   1.645 +};
   1.646 +
   1.647 +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)
   1.648 +{
   1.649 +    U x = 0;
   1.650 +    V y = 0;
   1.651 +    bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
   1.652 +    typename Result<U, V>::ResultType result = 0;
   1.653 +    overflowed |= !safeAdd(x, y, result);
   1.654 +    if (overflowed)
   1.655 +        return ResultOverflowed;
   1.656 +    return result;
   1.657 +}
   1.658 +
   1.659 +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)
   1.660 +{
   1.661 +    U x = 0;
   1.662 +    V y = 0;
   1.663 +    bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
   1.664 +    typename Result<U, V>::ResultType result = 0;
   1.665 +    overflowed |= !safeSub(x, y, result);
   1.666 +    if (overflowed)
   1.667 +        return ResultOverflowed;
   1.668 +    return result;
   1.669 +}
   1.670 +
   1.671 +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)
   1.672 +{
   1.673 +    U x = 0;
   1.674 +    V y = 0;
   1.675 +    bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
   1.676 +    typename Result<U, V>::ResultType result = 0;
   1.677 +    overflowed |= !safeMultiply(x, y, result);
   1.678 +    if (overflowed)
   1.679 +        return ResultOverflowed;
   1.680 +    return result;
   1.681 +}
   1.682 +
   1.683 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
   1.684 +{
   1.685 +    return lhs + Checked<V, OverflowHandler>(rhs);
   1.686 +}
   1.687 +
   1.688 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
   1.689 +{
   1.690 +    return lhs - Checked<V, OverflowHandler>(rhs);
   1.691 +}
   1.692 +
   1.693 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
   1.694 +{
   1.695 +    return lhs * Checked<V, OverflowHandler>(rhs);
   1.696 +}
   1.697 +
   1.698 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
   1.699 +{
   1.700 +    return Checked<U, OverflowHandler>(lhs) + rhs;
   1.701 +}
   1.702 +
   1.703 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
   1.704 +{
   1.705 +    return Checked<U, OverflowHandler>(lhs) - rhs;
   1.706 +}
   1.707 +
   1.708 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
   1.709 +{
   1.710 +    return Checked<U, OverflowHandler>(lhs) * rhs;
   1.711 +}
   1.712 +
   1.713 +}
   1.714 +
   1.715 +using WTF::Checked;
   1.716 +using WTF::RecordOverflow;
   1.717 +
   1.718 +#endif /* yarr_CheckedArithmetic_h */

mercurial