8#ifndef V8_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
9#define V8_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
27template <
typename NumericType>
29 std::is_floating_point_v<NumericType>
30 ? std::numeric_limits<NumericType>::max_exponent
31 : std::numeric_limits<NumericType>::digits + 1;
35template <
typename NumericType>
37 std::numeric_limits<NumericType>::digits + std::is_signed_v<NumericType>;
42 requires(std::is_arithmetic_v<T>)
44 if constexpr (std::is_signed_v<T>) {
55 requires std::is_integral_v<T>
57 using SignedT = std::make_signed_t<T>;
58 using UnsignedT = std::make_unsigned_t<T>;
59 return static_cast<SignedT
>((
static_cast<UnsignedT
>(
x) ^
60 static_cast<UnsignedT
>(-SignedT(is_negative))) +
66 requires std::is_integral_v<T>
68 using UnsignedT = std::make_unsigned_t<T>;
70 ?
static_cast<UnsignedT
>(0u -
static_cast<UnsignedT
>(
value))
71 :
static_cast<UnsignedT
>(
value);
91#elif defined(__GNUC__) || defined(__clang__)
94 ((void)(*(
volatile char*)0 = 0));
114template <
typename Dst,
typename Src,
128template <
typename Dst,
typename Src>
137template <
typename Dst,
typename Src>
147 constexpr RangeCheck(
bool is_in_lower_bound,
bool is_in_upper_bound)
187template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
194 SrcLimits::digits < DstLimits::digits)
195 ? (DstLimits::digits - SrcLimits::digits)
198 template <
typename T>
199 requires(std::same_as<T, Dst> &&
200 ((std::integral<T> &&
kShift < DstLimits::digits) ||
201 (std::floating_point<T> &&
kShift == 0)))
205 if constexpr (std::integral<T>) {
206 using UnsignedDst =
typename std::make_unsigned_t<T>;
207 return static_cast<T
>(
209 ~((UnsignedDst{1} <<
kShift) - UnsignedDst{1}),
216 static constexpr Dst
max() {
return Adjust(Bounds<Dst>::max()); }
217 static constexpr Dst
lowest() {
return Adjust(Bounds<Dst>::lowest()); }
226template <
typename Dst,
typename Src,
template <
typename>
class Bounds,
237 using SrcLimits = std::numeric_limits<Src>;
240 static_cast<Dst
>(SrcLimits::lowest()) >= DstLimits::lowest() ||
241 static_cast<Dst
>(value) >= DstLimits::lowest(),
242 static_cast<Dst
>(SrcLimits::max()) <= DstLimits::max() ||
243 static_cast<Dst
>(value) <= DstLimits::max());
249template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
255 return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
261template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
269 DstLimits::lowest() == Dst{0} || value >= DstLimits::lowest(),
270 value <= DstLimits::max());
275template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
282 using Promotion =
decltype(Src() + Dst());
283 return RangeCheck(DstLimits::lowest() <= Dst{0} ||
284 static_cast<Promotion
>(
value) >=
285 static_cast<Promotion
>(DstLimits::lowest()),
286 static_cast<Promotion
>(
value) <=
287 static_cast<Promotion
>(DstLimits::max()));
293template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
298 using SrcLimits = std::numeric_limits<Src>;
300 using Promotion =
decltype(Src() + Dst());
304 if constexpr (std::is_floating_point_v<Src>) {
305 ge_zero = value > Src{-1};
307 ge_zero = value >= Src{0};
310 ge_zero && (DstLimits::lowest() == 0 ||
311 static_cast<Dst
>(value) >= DstLimits::lowest()),
312 static_cast<Promotion
>(SrcLimits::max()) <=
313 static_cast<Promotion
>(DstLimits::max()) ||
314 static_cast<Promotion
>(value) <=
315 static_cast<Promotion
>(DstLimits::max()));
320template <
typename Dst,
typename Src>
321inline constexpr bool kIsTypeInRangeForNumericType =
325template <
typename Dst,
template <
typename>
class Bounds = std::numeric_limits,
327 requires(std::is_arithmetic_v<Src> && std::is_arithmetic_v<Dst> &&
328 Bounds<Dst>::lowest() < Bounds<Dst>::max())
334template <
size_t Size,
bool IsSigned>
337#define INTEGER_FOR_DIGITS_AND_SIGN(I) \
339 struct IntegerForDigitsAndSignImpl<kIntegerBitsPlusSign<I>, \
340 std::is_signed_v<I>> { \
352#undef INTEGER_FOR_DIGITS_AND_SIGN
354template <
size_t Size,
bool IsSigned>
362 "Max integer size not supported for this toolchain.");
364template <
typename Integer,
bool IsSigned = std::is_
signed_v<Integer>>
369template <
typename Lhs,
typename Rhs>
374template <
typename Lhs,
typename Rhs>
376 std::is_signed_v<Lhs>
384template <
typename Lhs,
typename Rhs = Lhs,
385 bool is_intmax_type =
386 std::is_integral_v<MaxExponentPromotion<Lhs, Rhs>> &&
401template <
typename Lhs,
typename Rhs>
405 std::is_signed_v<Lhs> || std::is_signed_v<Rhs>>;
410template <
typename Lhs,
typename Rhs>
416template <
typename Lhs,
typename Rhs>
419template <
typename Lhs,
typename Rhs>
427template <
typename T,
typename Lhs,
typename Rhs = Lhs>
429 !std::is_floating_point_v<T> && !std::is_floating_point_v<Lhs> &&
430 !std::is_floating_point_v<Rhs> &&
431 std::is_signed_v<T> >= std::is_signed_v<Lhs> &&
433 std::is_signed_v<T> >= std::is_signed_v<Rhs> &&
438template <
typename Lhs,
typename Rhs>
444template <
typename Lhs,
typename Rhs>
446 std::conditional_t<std::is_signed_v<Lhs> || std::is_signed_v<Rhs>,
447 intmax_t, uintmax_t>,
452 std::is_signed_v<Lhs> || std::is_signed_v<Rhs>>;
457template <
typename Lhs,
typename Rhs>
461template <
typename Lhs,
typename Rhs>
479 typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
484 requires std::is_arithmetic_v<T>
488 requires std::is_arithmetic_v<T>
492 requires std::is_arithmetic_v<T>
537inline constexpr bool kIsNumeric = std::is_arithmetic_v<UnderlyingType<T>>;
544template <
typename L,
typename R>
548template <
typename L,
typename R>
553template <
typename L,
typename R>
561template <
typename Src,
typename Dst = std::make_
signed_t<UnderlyingType<Src>>>
562 requires std::integral<Dst>
564 return static_cast<Dst
>(
value);
570template <
typename Src,
571 typename Dst = std::make_unsigned_t<UnderlyingType<Src>>>
572 requires std::integral<Dst>
574 return static_cast<Dst
>(
value);
577template <
typename L,
typename R>
578 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
580 using SumT =
decltype(std::declval<L>() + std::declval<R>());
581 static constexpr bool Test(L lhs, R rhs) {
585 (l_range == r_range &&
586 static_cast<SumT>(lhs) <
static_cast<SumT>(rhs));
590template <
typename L,
typename R>
591 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
593 using SumT =
decltype(std::declval<L>() + std::declval<R>());
594 static constexpr bool Test(L lhs, R rhs) {
598 (l_range == r_range &&
599 static_cast<SumT>(lhs) <=
static_cast<SumT>(rhs));
603template <
typename L,
typename R>
604 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
606 using SumT =
decltype(std::declval<L>() + std::declval<R>());
607 static constexpr bool Test(L lhs, R rhs) {
611 (l_range == r_range &&
612 static_cast<SumT>(lhs) >
static_cast<SumT>(rhs));
616template <
typename L,
typename R>
617 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
619 using SumT =
decltype(std::declval<L>() + std::declval<R>());
620 static constexpr bool Test(L lhs, R rhs) {
624 (l_range == r_range &&
625 static_cast<SumT>(lhs) >=
static_cast<SumT>(rhs));
629template <
typename L,
typename R>
630 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
632 using SumT =
decltype(std::declval<L>() + std::declval<R>());
633 static constexpr bool Test(L lhs, R rhs) {
636 static_cast<SumT>(lhs) ==
static_cast<SumT>(rhs);
640template <
typename L,
typename R>
641 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
643 using SumT =
decltype(std::declval<L>() + std::declval<R>());
644 static constexpr bool Test(L lhs, R rhs) {
647 static_cast<SumT>(lhs) !=
static_cast<SumT>(rhs);
653template <
template <
typename,
typename>
typename C,
typename L,
typename R>
654 requires std::is_arithmetic_v<L> && std::is_arithmetic_v<R>
659 ? C<BigType, BigType>::Test(
static_cast<BigType
>(lhs),
660 static_cast<BigType
>(rhs))
662 : C<L, R>::Test(lhs, rhs);
665template <
typename Dst,
typename Src>
668 std::numeric_limits<Src>::max());
670template <
typename Dst,
typename Src>
673 std::numeric_limits<Src>::lowest());
675template <
typename Dst,
typename Src>
678 ?
static_cast<Dst
>(std::numeric_limits<Src>::max())
679 :
std::numeric_limits<Dst>::max();
681template <
typename Dst,
typename Src>
684 ?
static_cast<Dst
>(std::numeric_limits<Src>::lowest())
685 : std::numeric_limits<Dst>::lowest();
690template <
typename Dst,
typename Src = Dst>
constexpr bool IsOverflow() const
constexpr bool IsUnderflowFlagSet() const
constexpr bool IsOverflowFlagSet() const
constexpr bool IsInvalid() const
constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
constexpr RangeCheck()=default
constexpr bool IsValid() const
constexpr bool IsUnderflow() const
constexpr bool operator==(const RangeCheck &rhs) const =default
constexpr auto ConditionalNegate(T x, bool is_negative)
constexpr auto SafeUnsignedAbs(T value)
constexpr bool IsValueNegative(T value)
constexpr bool kEnableAsmCode
constexpr bool SafeCompare(L lhs, R rhs)
constexpr int kIntegerBitsPlusSign
constexpr bool kIsNumeric
constexpr auto kStaticDstRangeRelationToSrcRange
constexpr auto as_unsigned(Src value)
UnderlyingTypeImpl< T >::type UnderlyingType
constexpr bool kIsClampedNumeric
BigEnoughPromotionImpl< Lhs, Rhs >::type BigEnoughPromotion
constexpr bool kIsBigEnoughPromotionContained
constexpr bool kIsCheckedNumeric
constexpr bool kIsMaxInRangeForNumericType
constexpr int kMaxExponent
constexpr bool kIsIntegerArithmeticSafe
std::conditional_t< std::is_signed_v< Lhs > ?(!std::is_signed_v< Rhs >||kMaxExponent< Lhs > > kMaxExponent< Rhs >) :(!std::is_signed_v< Rhs > &&kMaxExponent< Lhs >< kMaxExponent< Rhs >), Lhs, Rhs > LowestValuePromotion
constexpr bool kIsFastIntegerArithmeticPromotionContained
IntegerForDigitsAndSign< kIntegerBitsPlusSign< Integer > *2, IsSigned > TwiceWiderInteger
constexpr bool kIsStrictNumeric
constexpr Dst CommonMaxOrMin(bool is_min)
NumericRangeRepresentation
FastIntegerArithmeticPromotionImpl< Lhs, Rhs >::type FastIntegerArithmeticPromotion
typename std::conditional_t< std::is_enum_v< T >, std::underlying_type< T >, ArithmeticOrIntegralConstant< T > >::type ArithmeticOrUnderlyingEnum
constexpr bool kIsNumeric< T >
constexpr RangeCheck DstRangeRelationToSrcRange(Src value)
constexpr auto as_signed(Src value)
constexpr bool kIsMinInRangeForNumericType
std::conditional_t<(kMaxExponent< Lhs > > kMaxExponent< Rhs >), Lhs, Rhs > MaxExponentPromotion
IntegerForDigitsAndSignImpl< Size, IsSigned >::type IntegerForDigitsAndSign
#define INTEGER_FOR_DIGITS_AND_SIGN(I)
static constexpr RangeCheck Check(Src value)
static constexpr RangeCheck Check(Src value)
static constexpr RangeCheck Check(Src value)
static constexpr RangeCheck Check(Src value)
static constexpr RangeCheck Check(Src value)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr bool Test(L lhs, R rhs)
static constexpr bool Test(L lhs, R rhs)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr bool Test(L lhs, R rhs)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr bool Test(L lhs, R rhs)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr bool Test(L lhs, R rhs)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr bool Test(L lhs, R rhs)
decltype(std::declval< L >()+std::declval< R >()) SumT
static constexpr int kShift
static constexpr T Adjust(T value)
static constexpr Dst max()
static constexpr Dst lowest()
std::numeric_limits< Dst > DstLimits
std::numeric_limits< Src > SrcLimits
ArithmeticOrUnderlyingEnum< T > type
std::unique_ptr< ValueMirror > value