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_IMPL_H_
93ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#define V8_BASE_SAFE_MATH_IMPL_H_
103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include <stdint.h>
123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include <cmath>
143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include <cstdlib>
153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include <limits>
163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include "src/base/macros.h"
183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#include "src/base/safe_conversions.h"
193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace v8 {
213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace base {
223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgnamespace internal {
233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// From Chromium's base/template_util.h:
263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate<class T, T v>
283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct integral_constant {
293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static const T value = v;
303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef T value_type;
313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef integral_constant<T, v> type;
323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <class T, T v> const T integral_constant<T, v>::value;
353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypedef integral_constant<bool, true> true_type;
373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypedef integral_constant<bool, false> false_type;
383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <class T, class U> struct is_same : public false_type {};
403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <class T> struct is_same<T, T> : true_type {};
413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate<bool B, class T = void>
433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct enable_if {};
443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate<class T>
463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct enable_if<true, T> { typedef T type; };
473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// </template_util.h>
493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Everything from here up to the floating point operations is portable C++,
523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// but it may not be fast. This code could be split based on
533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// platform/architecture and replaced with potentially faster implementations.
543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Integer promotion templates used by the portable checked integer arithmetic.
563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <size_t Size, bool IsSigned>
573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign;
583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<1, true> {
603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef int8_t type;
613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<1, false> {
643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef uint8_t type;
653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<2, true> {
683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef int16_t type;
693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<2, false> {
723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef uint16_t type;
733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<4, true> {
763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef int32_t type;
773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<4, false> {
803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef uint32_t type;
813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<8, true> {
843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef int64_t type;
853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <>
873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IntegerForSizeAndSign<8, false> {
883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef uint64_t type;
893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// support 128-bit math, then the ArithmeticPromotion template below will need
933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// to be updated (or more likely replaced with a decltype expression).
943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Integer>
963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct UnsignedIntegerForSize {
973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename enable_if<
983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      std::numeric_limits<Integer>::is_integer,
993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
1003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
1013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Integer>
1033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct SignedIntegerForSize {
1043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename enable_if<
1053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      std::numeric_limits<Integer>::is_integer,
1063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
1073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
1083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Integer>
1103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct TwiceWiderInteger {
1113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename enable_if<
1123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      std::numeric_limits<Integer>::is_integer,
1133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename IntegerForSizeAndSign<
1143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          sizeof(Integer) * 2,
1153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          std::numeric_limits<Integer>::is_signed>::type>::type type;
1163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
1173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Integer>
1193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct PositionOfSignBit {
1203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static const typename enable_if<std::numeric_limits<Integer>::is_integer,
1213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                  size_t>::type value = 8 * sizeof(Integer) - 1;
1223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
1233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Helper templates for integer manipulations.
1253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
1273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgbool HasSignBit(T x) {
1283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Cast to unsigned since right shift on signed is undefined.
1293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
1303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org            PositionOfSignBit<T>::value);
1313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
1323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// This wrapper undoes the standard integer promotions.
1343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
1353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgT BinaryComplement(T x) {
1363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return ~x;
1373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
1383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Here are the actual portable checked integer math implementations.
1403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
1413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// way to coalesce things into the CheckedNumericState specializations below.
1423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
1443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_integer, T>::type
1453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedAdd(T x, T y, RangeConstraint* validity) {
1463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Since the value of x+y is undefined if we have a signed type, we compute
1473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // it using the unsigned type of the same size.
1483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
1493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst ux = static_cast<UnsignedDst>(x);
1503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst uy = static_cast<UnsignedDst>(y);
1513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst uresult = ux + uy;
1523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Addition is valid if the sign of (x + y) is equal to either that of x or
1533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // that of y.
1543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  if (std::numeric_limits<T>::is_signed) {
1553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
1563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = RANGE_VALID;
1573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    else  // Direction of wrap is inverse of result sign.
1583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
1593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  } else {  // Unsigned is either valid or overflow.
1613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
1623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return static_cast<T>(uresult);
1643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
1653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
1673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_integer, T>::type
1683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedSub(T x, T y, RangeConstraint* validity) {
1693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Since the value of x+y is undefined if we have a signed type, we compute
1703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // it using the unsigned type of the same size.
1713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
1723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst ux = static_cast<UnsignedDst>(x);
1733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst uy = static_cast<UnsignedDst>(y);
1743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  UnsignedDst uresult = ux - uy;
1753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Subtraction is valid if either x and y have same sign, or (x-y) and x have
1763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // the same sign.
1773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  if (std::numeric_limits<T>::is_signed) {
1783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
1793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = RANGE_VALID;
1803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    else  // Direction of wrap is inverse of result sign.
1813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
1823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  } else {  // Unsigned is either valid or underflow.
1843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
1853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
1863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return static_cast<T>(uresult);
1873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
1883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
1893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Integer multiplication is a bit complicated. In the fast case we just
1903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// we just promote to a twice wider type, and range check the result. In the
1913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// slow case we need to manually check that the result won't be truncated by
1923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// checking with division against the appropriate bound.
1933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
1943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
1953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t),
1963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
1973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedMul(T x, T y, RangeConstraint* validity) {
1983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef typename TwiceWiderInteger<T>::type IntermediateType;
1993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  IntermediateType tmp =
2003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
2013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = DstRangeRelationToSrcRange<T>(tmp);
2023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return static_cast<T>(tmp);
2033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_integer &&
2073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                       std::numeric_limits<T>::is_signed &&
2083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                       (sizeof(T) * 2 > sizeof(uintmax_t)),
2093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                   T>::type
2103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedMul(T x, T y, RangeConstraint* validity) {
2113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // if either side is zero then the result will be zero.
2123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  if (!(x || y)) {
2133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return RANGE_VALID;
2143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  } else if (x > 0) {
2163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (y > 0)
2173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity =
2183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
2193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    else
2203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
2213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                                         : RANGE_UNDERFLOW;
2223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  } else {
2243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    if (y > 0)
2253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
2263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                                         : RANGE_UNDERFLOW;
2273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    else
2283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      *validity =
2293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
2303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
2313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return x * y;
2333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_integer &&
2373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                       !std::numeric_limits<T>::is_signed &&
2383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                       (sizeof(T) * 2 > sizeof(uintmax_t)),
2393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                   T>::type
2403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedMul(T x, T y, RangeConstraint* validity) {
2413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
2423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                  ? RANGE_VALID
2433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                  : RANGE_OVERFLOW;
2443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return x * y;
2453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Division just requires a check for an invalid negation on signed min/-1.
2483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgT CheckedDiv(
2503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T x,
2513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T y,
2523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint* validity,
2533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) {
2543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
2553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      y == static_cast<T>(-1)) {
2563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    *validity = RANGE_OVERFLOW;
2573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return std::numeric_limits<T>::min();
2583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
2593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = RANGE_VALID;
2613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return x / y;
2623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
2663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
2673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
2683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedMod(T x, T y, RangeConstraint* validity) {
2693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
2703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return x % y;
2713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
2753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
2763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
2773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedMod(T x, T y, RangeConstraint* validity) {
2783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = RANGE_VALID;
2793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return x % y;
2803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
2843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
2853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
2863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedNeg(T value, RangeConstraint* validity) {
2873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity =
2883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
2893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // The negation of signed min is min, so catch that one.
2903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return -value;
2913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
2923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
2933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
2943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
2953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
2963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
2973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedNeg(T value, RangeConstraint* validity) {
2983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // The only legal unsigned negation is zero.
2993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
3003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return static_cast<T>(
3013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      -static_cast<typename SignedIntegerForSize<T>::type>(value));
3023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
3053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
3063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
3073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
3083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedAbs(T value, RangeConstraint* validity) {
3093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity =
3103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
3113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return std::abs(value);
3123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
3153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<
3163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
3173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T>::type
3183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgCheckedAbs(T value, RangeConstraint* validity) {
3193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Absolute value of a positive is just its identiy.
3203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  *validity = RANGE_VALID;
3213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return value;
3223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// These are the floating point stubs that the compiler needs to see. Only the
3253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// negation operation is ever called.
3263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#define BASE_FLOAT_ARITHMETIC_STUBS(NAME)                        \
3273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename T>                                          \
3283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \
3293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  Checked##NAME(T, T, RangeConstraint*) {                        \
3303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    UNREACHABLE();                                               \
3313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return 0;                                                    \
3323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
3333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_FLOAT_ARITHMETIC_STUBS(Add)
3353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_FLOAT_ARITHMETIC_STUBS(Sub)
3363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_FLOAT_ARITHMETIC_STUBS(Mul)
3373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_FLOAT_ARITHMETIC_STUBS(Div)
3383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgBASE_FLOAT_ARITHMETIC_STUBS(Mod)
3393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#undef BASE_FLOAT_ARITHMETIC_STUBS
3413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
3433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
3443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T value,
3453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint*) {
3463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return -value;
3473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
3503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtypename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
3513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    T value,
3523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    RangeConstraint*) {
3533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  return std::abs(value);
3543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Floats carry around their validity state with them, but integers do not. So,
3573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// we wrap the underlying value in a specialization in order to hide that detail
3583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// and expose an interface via accessors.
3593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgenum NumericRepresentation {
3603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  NUMERIC_INTEGER,
3613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  NUMERIC_FLOATING,
3623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  NUMERIC_UNKNOWN
3633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
3643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename NumericType>
3663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct GetNumericRepresentation {
3673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static const NumericRepresentation value =
3683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      std::numeric_limits<NumericType>::is_integer
3693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          ? NUMERIC_INTEGER
3703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
3713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                                         : NUMERIC_UNKNOWN);
3723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
3733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T, NumericRepresentation type =
3753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                          GetNumericRepresentation<T>::value>
3763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgclass CheckedNumericState {};
3773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Integrals require quite a bit of additional housekeeping to manage state.
3793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
3803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgclass CheckedNumericState<T, NUMERIC_INTEGER> {
3813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org private:
3823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T value_;
3833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  RangeConstraint validity_;
3843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org public:
3863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src, NumericRepresentation type>
3873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  friend class CheckedNumericState;
3883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
3903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
3923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState(Src value, RangeConstraint validity)
3933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : value_(value),
3943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        validity_(GetRangeConstraint(validity |
3953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                     DstRangeRelationToSrcRange<T>(value))) {
3963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    // Argument must be numeric.
3973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    STATIC_ASSERT(std::numeric_limits<Src>::is_specialized);
3983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
3993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Copy constructor.
4013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
4023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState(const CheckedNumericState<Src>& rhs)
4033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : value_(static_cast<T>(rhs.value())),
4043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        validity_(GetRangeConstraint(
4053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org            rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
4063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
4083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  explicit CheckedNumericState(
4093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      Src value,
4103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
4113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          0)
4123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : value_(static_cast<T>(value)),
4133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        validity_(DstRangeRelationToSrcRange<T>(value)) {}
4143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  RangeConstraint validity() const { return validity_; }
4163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T value() const { return value_; }
4173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
4183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// Floating points maintain their own validity, but need translation wrappers.
4203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T>
4213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgclass CheckedNumericState<T, NUMERIC_FLOATING> {
4223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org private:
4233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T value_;
4243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org public:
4263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src, NumericRepresentation type>
4273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  friend class CheckedNumericState;
4283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState() : value_(0.0) {}
4303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
4323ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState(
4333ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      Src value,
4343ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      RangeConstraint validity,
4353ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
4363ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    switch (DstRangeRelationToSrcRange<T>(value)) {
4373ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      case RANGE_VALID:
4383ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        value_ = static_cast<T>(value);
4393ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        break;
4403ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4413ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      case RANGE_UNDERFLOW:
4423ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        value_ = -std::numeric_limits<T>::infinity();
4433ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        break;
4443ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4453ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      case RANGE_OVERFLOW:
4463ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        value_ = std::numeric_limits<T>::infinity();
4473ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        break;
4483ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4493ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      case RANGE_INVALID:
4503ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        value_ = std::numeric_limits<T>::quiet_NaN();
4513ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org        break;
4523ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    }
4533ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
4543ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4553ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
4563ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  explicit CheckedNumericState(
4573ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      Src value,
4583ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
4593ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          0)
4603ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : value_(static_cast<T>(value)) {}
4613ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4623ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  // Copy constructor.
4633ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  template <typename Src>
4643ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  CheckedNumericState(const CheckedNumericState<Src>& rhs)
4653ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org      : value_(static_cast<T>(rhs.value())) {}
4663ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4673ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  RangeConstraint validity() const {
4683ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org    return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
4693ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                              value_ >= -std::numeric_limits<T>::max());
4703ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  }
4713ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  T value() const { return value_; }
4723ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
4733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// For integers less than 128-bit and floats 32-bit or larger, we can distil
4753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// C/C++ arithmetic promotions down to two simple rules:
4763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// 1. The type with the larger maximum exponent always takes precedence.
4773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// 2. The resulting type must be promoted to at least an int.
4783ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// The following template specializations implement that promotion logic.
4793ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgenum ArithmeticPromotionCategory {
4803ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  LEFT_PROMOTION,
4813ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  RIGHT_PROMOTION,
4823ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  DEFAULT_PROMOTION
4833ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
4843ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4853ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Lhs,
4863ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          typename Rhs = Lhs,
4873ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org          ArithmeticPromotionCategory Promotion =
4883ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
4893ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                  ? (MaxExponent<Lhs>::value > MaxExponent<int>::value
4903ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                         ? LEFT_PROMOTION
4913ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                         : DEFAULT_PROMOTION)
4923ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                  : (MaxExponent<Rhs>::value > MaxExponent<int>::value
4933ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                         ? RIGHT_PROMOTION
4943ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                         : DEFAULT_PROMOTION) >
4953ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct ArithmeticPromotion;
4963ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
4973ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Lhs, typename Rhs>
4983ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
4993ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef Lhs type;
5003ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
5013ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
5023ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Lhs, typename Rhs>
5033ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
5043ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef Rhs type;
5053ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
5063ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
5073ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename Lhs, typename Rhs>
5083ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
5093ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  typedef int type;
5103ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
5113ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
5123ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// We can statically check if operations on the provided types can wrap, so we
5133ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// can skip the checked operations if they're not needed. So, for an integer we
5143ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// care if the destination type preserves the sign and is twice the width of
5153ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org// the source.
5163ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgtemplate <typename T, typename Lhs, typename Rhs>
5173ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.orgstruct IsIntegerArithmeticSafe {
5183ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org  static const bool value = !std::numeric_limits<T>::is_iec559 &&
5193ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                            StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
5203ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                NUMERIC_RANGE_CONTAINED &&
5213ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                            sizeof(T) >= (2 * sizeof(Lhs)) &&
5223ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                            StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
5233ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                                NUMERIC_RANGE_CONTAINED &&
5243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org                            sizeof(T) >= (2 * sizeof(Rhs));
5253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org};
5263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
5273ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace internal
5283ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace base
5293ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}  // namespace v8
5303ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
5313ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#endif  // V8_BASE_SAFE_MATH_IMPL_H_
532