8 #ifndef V8_BASE_SAFE_MATH_IMPL_H_ 9 #define V8_BASE_SAFE_MATH_IMPL_H_ 17 #include "src/base/macros.h" 18 #include "src/base/safe_conversions.h" 27 template<
class T, T v>
29 static const T value = v;
42 template<
bool B,
class T =
void>
56 template <
size_t Size,
bool IsSigned>
72 typedef uint16_t type;
88 typedef uint64_t type;
95 template <
typename Integer>
98 std::numeric_limits<Integer>::is_integer,
102 template <
typename Integer>
105 std::numeric_limits<Integer>::is_integer,
109 template <
typename Integer>
112 std::numeric_limits<Integer>::is_integer,
115 std::numeric_limits<Integer>::is_signed>::type>::type type;
118 template <
typename Integer>
121 size_t>::type value = 8 *
sizeof(
Integer) - 1;
126 template <
typename T>
127 bool HasSignBit(
T x) {
129 return !!(
static_cast<typename UnsignedIntegerForSize<T>::type
>(x) >>
134 template <
typename T>
135 T BinaryComplement(T x) {
143 template <
typename T>
144 typename enable_if<std::numeric_limits<T>::is_integer,
T>
::type 145 CheckedAdd(
T x,
T y, RangeConstraint* validity) {
148 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
149 UnsignedDst ux =
static_cast<UnsignedDst
>(x);
150 UnsignedDst uy =
static_cast<UnsignedDst
>(y);
151 UnsignedDst uresult = ux + uy;
154 if (std::numeric_limits<T>::is_signed) {
155 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
156 *validity = RANGE_VALID;
158 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
161 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
163 return static_cast<T
>(uresult);
166 template <
typename T>
167 typename enable_if<std::numeric_limits<T>::is_integer, T>::type
168 CheckedSub(T x, T y, RangeConstraint* validity) {
171 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
172 UnsignedDst ux =
static_cast<UnsignedDst
>(x);
173 UnsignedDst uy =
static_cast<UnsignedDst
>(y);
174 UnsignedDst uresult = ux - uy;
177 if (std::numeric_limits<T>::is_signed) {
178 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
179 *validity = RANGE_VALID;
181 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
184 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
186 return static_cast<T
>(uresult);
193 template <
typename T>
195 std::numeric_limits<T>::is_integer &&
sizeof(T) * 2 <=
sizeof(uintmax_t),
197 CheckedMul(T x, T y, RangeConstraint* validity) {
198 typedef typename TwiceWiderInteger<T>::type IntermediateType;
199 IntermediateType tmp =
200 static_cast<IntermediateType
>(x) * static_cast<IntermediateType>(y);
201 *validity = DstRangeRelationToSrcRange<T>(tmp);
202 return static_cast<T
>(tmp);
205 template <
typename T>
206 typename enable_if<std::numeric_limits<T>::is_integer &&
207 std::numeric_limits<T>::is_signed &&
208 (
sizeof(T) * 2 >
sizeof(uintmax_t)),
210 CheckedMul(T x, T y, RangeConstraint* validity) {
218 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
220 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
225 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
229 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
235 template <
typename T>
236 typename enable_if<std::numeric_limits<T>::is_integer &&
237 !std::numeric_limits<T>::is_signed &&
238 (
sizeof(T) * 2 >
sizeof(uintmax_t)),
240 CheckedMul(T x, T y, RangeConstraint* validity) {
241 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
248 template <
typename T>
252 RangeConstraint* validity,
253 typename enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0) {
254 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
255 y == static_cast<T>(-1)) {
256 *validity = RANGE_OVERFLOW;
257 return std::numeric_limits<T>::min();
260 *validity = RANGE_VALID;
264 template <
typename T>
266 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
268 CheckedMod(T x, T y, RangeConstraint* validity) {
269 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
273 template <
typename T>
275 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
277 CheckedMod(T x, T y, RangeConstraint* validity) {
278 *validity = RANGE_VALID;
282 template <
typename T>
284 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
286 CheckedNeg(T value, RangeConstraint* validity) {
288 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
293 template <
typename T>
295 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
297 CheckedNeg(T value, RangeConstraint* validity) {
299 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
300 return static_cast<T
>(
301 -
static_cast<typename SignedIntegerForSize<T>::type
>(value));
304 template <
typename T>
306 std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed,
308 CheckedAbs(T value, RangeConstraint* validity) {
310 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
311 return std::abs(value);
314 template <
typename T>
316 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
318 CheckedAbs(T value, RangeConstraint* validity) {
320 *validity = RANGE_VALID;
326 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ 327 template <typename T> \ 328 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ 329 Checked##NAME(T, T, RangeConstraint*) { \ 334 BASE_FLOAT_ARITHMETIC_STUBS(Add)
335 BASE_FLOAT_ARITHMETIC_STUBS(Sub)
336 BASE_FLOAT_ARITHMETIC_STUBS(Mul)
337 BASE_FLOAT_ARITHMETIC_STUBS(Div)
338 BASE_FLOAT_ARITHMETIC_STUBS(Mod)
340 #undef BASE_FLOAT_ARITHMETIC_STUBS 342 template <
typename T>
343 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
349 template <
typename T>
350 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
353 return std::abs(value);
359 enum NumericRepresentation {
365 template <
typename NumericType>
367 static const NumericRepresentation value =
368 std::numeric_limits<NumericType>::is_integer
370 : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
374 template <
typename T, NumericRepresentation
type =
379 template <
typename T>
383 RangeConstraint validity_;
386 template <
typename Src, NumericRepresentation type>
391 template <
typename Src>
394 validity_(GetRangeConstraint(validity |
395 DstRangeRelationToSrcRange<T>(value))) {
397 STATIC_ASSERT(std::numeric_limits<Src>::is_specialized);
401 template <
typename Src>
403 : value_(static_cast<T>(rhs.value())),
404 validity_(GetRangeConstraint(
405 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
407 template <
typename Src>
410 typename enable_if<std::numeric_limits<Src>::is_specialized,
int>::
type =
412 : value_(static_cast<T>(value)),
413 validity_(DstRangeRelationToSrcRange<T>(value)) {}
415 RangeConstraint validity()
const {
return validity_; }
416 T value()
const {
return value_; }
420 template <
typename T>
426 template <
typename Src, NumericRepresentation type>
431 template <
typename Src>
434 RangeConstraint validity,
435 typename enable_if<std::numeric_limits<Src>::is_integer,
int>::
type = 0) {
436 switch (DstRangeRelationToSrcRange<T>(value)) {
438 value_ =
static_cast<T>(value);
441 case RANGE_UNDERFLOW:
442 value_ = -std::numeric_limits<T>::infinity();
446 value_ = std::numeric_limits<T>::infinity();
450 value_ = std::numeric_limits<T>::quiet_NaN();
455 template <
typename Src>
458 typename enable_if<std::numeric_limits<Src>::is_specialized,
int>::
type =
460 : value_(static_cast<T>(value)) {}
463 template <
typename Src>
465 : value_(static_cast<T>(rhs.value())) {}
467 RangeConstraint validity()
const {
468 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
469 value_ >= -std::numeric_limits<T>::max());
471 T value()
const {
return value_; }
479 enum ArithmeticPromotionCategory {
485 template <
typename Lhs,
487 ArithmeticPromotionCategory Promotion =
488 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
489 ? (MaxExponent<Lhs>::value > MaxExponent<int>::value
492 : (MaxExponent<Rhs>::value > MaxExponent<int>::value
494 : DEFAULT_PROMOTION) >
497 template <
typename Lhs,
typename Rhs>
502 template <
typename Lhs,
typename Rhs>
507 template <
typename Lhs,
typename Rhs>
516 template <
typename T,
typename Lhs,
typename Rhs>
518 static const bool value = !std::numeric_limits<T>::is_iec559 &&
520 NUMERIC_RANGE_CONTAINED &&
521 sizeof(
T) >= (2 *
sizeof(Lhs)) &&
523 NUMERIC_RANGE_CONTAINED &&
524 sizeof(
T) >= (2 *
sizeof(Rhs));
531 #endif // V8_BASE_SAFE_MATH_IMPL_H_