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