13ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved.
23ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Use of this source code is governed by a BSD-style license that can be
33ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// found in the LICENSE file.
43ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
53ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Slightly adapted for inclusion in V8.
63ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Copyright 2014 the V8 project authors. All rights reserved.
73ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
83ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#ifndef V8_BASE_SAFE_MATH_H_
93ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#define V8_BASE_SAFE_MATH_H_
103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include "src/base/safe_math_impl.h"
123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace v8 {
143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace base {
153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace internal {
163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// CheckedNumeric implements all the logic and operators for detecting integer
183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// boundary conditions such as overflow, underflow, and invalid conversions.
193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// The CheckedNumeric type implicitly converts from floating point and integer
203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// data types, and contains overloads for basic arithmetic operations (i.e.: +,
213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// -, *, /, %).
223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//
233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// The following methods convert from CheckedNumeric to standard numeric values:
243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//             has not wrapped and is not the result of an invalid conversion).
263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// ValueOrDie() - Returns the underlying value. If the state is not valid this
273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//                call will crash on a CHECK.
283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// ValueOrDefault() - Returns the current value, or the supplied default if the
293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//                    state is not valid.
303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// ValueFloating() - Returns the underlying floating point value (valid only
313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//                   only for floating point CheckedNumeric types).
323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//
333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Bitwise operations are explicitly not supported, because correct
343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// operations are explicitly not supported because they could result in a crash
363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// on a CHECK condition. You should use patterns like the following for these
373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// operations:
383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Bitwise operation:
393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//     CheckedNumeric<int> checked_int = untrusted_input_value;
403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//     int x = checked_int.ValueOrDefault(0) | kFlagValues;
413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Comparison:
423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//   CheckedNumeric<size_t> checked_size;
433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//   CheckedNumeric<int> checked_size = untrusted_input_value;
443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//   checked_size = checked_size + HEADER LENGTH;
453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//     Do stuff...
473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgclass CheckedNumeric {
493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org public:
503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef T type;
513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric() {}
533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Copy constructor.
553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric(const CheckedNumeric<Src>& rhs)
573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : state_(rhs.ValueUnsafe(), rhs.validity()) {}
583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric(Src value, RangeConstraint validity)
613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : state_(value, validity) {}
623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // This is not an explicit constructor because we implicitly upgrade regular
643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // numerics to CheckedNumerics to make them easier to use.
653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric(Src value)  // NOLINT
673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : state_(value) {
683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    // Argument must be numeric.
693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    STATIC_ASSERT(std::numeric_limits<Src>::is_specialized);
703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // IsValid() is the public API to test if a CheckedNumeric is currently valid.
733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  bool IsValid() const { return validity() == RANGE_VALID; }
743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // ValueOrDie() The primary accessor for the underlying value. If the current
763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // state is not valid it will CHECK and crash.
773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T ValueOrDie() const {
783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    CHECK(IsValid());
793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return state_.value();
803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // ValueOrDefault(T default_value) A convenience method that returns the
833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // current value if the state is valid, and the supplied default_value for
843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // any other state.
853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T ValueOrDefault(T default_value) const {
863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return IsValid() ? state_.value() : default_value;
873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // ValueFloating() - Since floating point values include their validity state,
903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // we provide an easy method for extracting them directly, without a risk of
913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // crashing on a CHECK.
923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T ValueFloating() const {
933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    // Argument must be a floating-point value.
943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<T>::cast(*this).ValueUnsafe();
963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // tests and to avoid a big matrix of friend operator overloads. But the
1003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // values it returns are likely to change in the future.
1013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Returns: current validity state (i.e. valid, overflow, underflow, nan).
1023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
1033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // saturation/wrapping so we can expose this state consistently and implement
1043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // saturated arithmetic.
1053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  RangeConstraint validity() const { return state_.validity(); }
1063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
1083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // for tests and to avoid a big matrix of friend operator overloads. But the
1093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // values it returns are likely to change in the future.
1103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Returns: the raw numeric value, regardless of the current state.
1113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
1123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // saturation/wrapping so we can expose this state consistently and implement
1133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // saturated arithmetic.
1143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T ValueUnsafe() const { return state_.value(); }
1153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Prototypes for the supported arithmetic operator overloads.
1173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src> CheckedNumeric& operator+=(Src rhs);
1183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src> CheckedNumeric& operator-=(Src rhs);
1193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src> CheckedNumeric& operator*=(Src rhs);
1203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src> CheckedNumeric& operator/=(Src rhs);
1213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src> CheckedNumeric& operator%=(Src rhs);
1223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric operator-() const {
1243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint validity;
1253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T value = CheckedNeg(state_.value(), &validity);
1263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    // Negation is always valid for floating point.
1273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (std::numeric_limits<T>::is_iec559)
1283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<T>(value);
1293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    validity = GetRangeConstraint(state_.validity() | validity);
1313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<T>(value, validity);
1323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric Abs() const {
1353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint validity;
1363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T value = CheckedAbs(state_.value(), &validity);
1373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    // Absolute value is always valid for floating point.
1383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (std::numeric_limits<T>::is_iec559)
1393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<T>(value);
1403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    validity = GetRangeConstraint(state_.validity() | validity);
1423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<T>(value, validity);
1433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric& operator++() {
1463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *this += 1;
1473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return *this;
1483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric operator++(int) {
1513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    CheckedNumeric value = *this;
1523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *this += 1;
1533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return value;
1543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric& operator--() {
1573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *this -= 1;
1583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return *this;
1593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric operator--(int) {
1623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    CheckedNumeric value = *this;
1633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *this -= 1;
1643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return value;
1653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // These static methods behave like a convenience cast operator targeting
1683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // the desired CheckedNumeric type. As an optimization, a reference is
1693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // returned when Src is the same type as T.
1703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
1713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static CheckedNumeric<T> cast(
1723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      Src u,
1733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
1743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          0) {
1753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return u;
1763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
1793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static CheckedNumeric<T> cast(
1803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      const CheckedNumeric<Src>& u,
1813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
1823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return u;
1833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
1863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org private:
1883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState<T> state_;
1893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
1903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// This is the boilerplate for the standard arithmetic operator overloads. A
1923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// macro isn't the prettiest solution, but it beats rewriting these five times.
1933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Some details worth noting are:
1943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//  * We apply the standard arithmetic promotions.
1953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//  * We skip range checks for floating points.
1963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org//  * We skip range checks for destination integers with sufficient range.
1973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// TODO(jschuh): extract these out into templates.
1983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)              \
1993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  /* Binary arithmetic operator for CheckedNumerics of the same type. */      \
2003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T>                                                       \
2013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP(          \
2023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) {           \
2033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    typedef typename ArithmeticPromotion<T>::type Promotion;                  \
2043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    /* Floating point always takes the fast path */                           \
2053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (std::numeric_limits<T>::is_iec559)                                    \
2063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());       \
2073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (IsIntegerArithmeticSafe<Promotion, T, T>::value)                      \
2083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<Promotion>(                                       \
2093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
2103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
2113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint validity = RANGE_VALID;                                   \
2123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T result = Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()),       \
2133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                             static_cast<Promotion>(rhs.ValueUnsafe()),       \
2143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                             &validity);                                      \
2153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<Promotion>(                                         \
2163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        result,                                                               \
2173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        GetRangeConstraint(validity | lhs.validity() | rhs.validity()));      \
2183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }                                                                           \
2193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  /* Assignment arithmetic operator implementation from CheckedNumeric. */    \
2203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T>                                                       \
2213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>                                                     \
2223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) {       \
2233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
2243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return *this;                                                             \
2253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }                                                                           \
2263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  /* Binary arithmetic operator for CheckedNumeric of different type. */      \
2273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T, typename Src>                                         \
2283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
2293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) {         \
2303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
2313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
2323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<Promotion>(                                       \
2333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
2343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
2353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<Promotion>::cast(lhs)                               \
2363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        OP CheckedNumeric<Promotion>::cast(rhs);                              \
2373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }                                                                           \
2383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
2393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T, typename Src>                                         \
2403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
2413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      const CheckedNumeric<T>& lhs, Src rhs) {                                \
2423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
2433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
2443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs,              \
2453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                       lhs.validity());                       \
2463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<Promotion>::cast(lhs)                               \
2473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        OP CheckedNumeric<Promotion>::cast(rhs);                              \
2483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }                                                                           \
2493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
2503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T, typename Src>                                         \
2513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
2523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      Src lhs, const CheckedNumeric<T>& rhs) {                                \
2533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
2543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
2553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(),              \
2563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                       rhs.validity());                       \
2573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return CheckedNumeric<Promotion>::cast(lhs)                               \
2583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        OP CheckedNumeric<Promotion>::cast(rhs);                              \
2593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
2603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
2623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
2633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
2643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
2653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
2663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
2683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace internal
2703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgusing internal::CheckedNumeric;
2723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace base
2743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace v8
2753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#endif  // V8_BASE_SAFE_MATH_H_
277