5#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
6#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
12#if defined(__GNUC__) || defined(__clang__)
13#define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
14#define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
16#define BASE_NUMERICS_LIKELY(x) (x)
17#define BASE_NUMERICS_UNLIKELY(x) (x)
25template <
typename NumericType>
28 ? std::numeric_limits<NumericType>::max_exponent
29 : std::numeric_limits<NumericType>::digits + 1;
34template <
typename NumericType>
36 static const int value = std::numeric_limits<NumericType>::digits +
42template <
typename Integer>
73 return static_cast<SignedT
>(
74 (
static_cast<UnsignedT
>(
x) ^ -SignedT(is_negative)) + is_negative);
83 ?
static_cast<UnsignedT
>(0u -
static_cast<UnsignedT
>(
value))
84 :
static_cast<UnsignedT
>(
value);
88#if defined(__clang__) || defined(__GNUC__)
94 return __builtin_constant_p(v);
116 template <
typename T>
120#elif defined(__GNUC__) || defined(__clang__)
123 ((void)(*(
volatile char*)0 = 0));
147template <
typename Dst,
159template <
typename Dst,
typename Src, IntegerRepresentation Sign>
169template <
typename Dst,
typename Src>
181template <
typename Dst,
typename Src>
193 constexpr RangeCheck(
bool is_in_lower_bound,
bool is_in_upper_bound)
194 : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
195 constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
196 constexpr bool IsValid()
const {
return !is_overflow_ && !is_underflow_; }
197 constexpr bool IsInvalid()
const {
return is_overflow_ && is_underflow_; }
198 constexpr bool IsOverflow()
const {
return is_overflow_ && !is_underflow_; }
199 constexpr bool IsUnderflow()
const {
return !is_overflow_ && is_underflow_; }
203 return is_underflow_ == rhs.is_underflow_ &&
204 is_overflow_ == rhs.is_overflow_;
207 return !(*
this == rhs);
213 const bool is_underflow_;
214 const bool is_overflow_;
238template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
246 SrcLimits::digits < DstLimits::digits)
247 ? (DstLimits::digits - SrcLimits::digits)
257 static_assert(
kShift < DstLimits::digits,
"");
258 return static_cast<T>(
263 template <
typename T,
268 static_assert(
kShift == 0,
"");
273 static constexpr Dst
lowest() {
return Adjust(Bounds<Dst>::lowest()); }
276template <
typename Dst,
295template <
typename Dst,
308 using SrcLimits = std::numeric_limits<Src>;
311 static_cast<Dst
>(SrcLimits::lowest()) >= DstLimits::lowest() ||
312 static_cast<Dst
>(
value) >= DstLimits::lowest(),
320template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
335template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
345 DstLimits::lowest() == Dst(0) ||
value >= DstLimits::lowest(),
351template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
360 using Promotion =
decltype(Src() + Dst());
361 return RangeCheck(DstLimits::lowest() <= Dst(0) ||
362 static_cast<Promotion
>(
value) >=
363 static_cast<Promotion
>(DstLimits::lowest()),
364 static_cast<Promotion
>(
value) <=
371template <
typename Dst,
typename Src,
template <
typename>
class Bounds>
379 using SrcLimits = std::numeric_limits<Src>;
381 using Promotion =
decltype(Src() + Dst());
383 value >= Src(0) && (DstLimits::lowest() == 0 ||
384 static_cast<Dst
>(
value) >= DstLimits::lowest()),
387 static_cast<Promotion
>(
value) <=
393template <
typename Dst,
typename Src>
399template <
typename Dst,
400 template <
typename>
class Bounds = std::numeric_limits,
410template <
size_t Size,
bool IsSigned>
413#define INTEGER_FOR_DIGITS_AND_SIGN(I) \
415 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
416 std::is_signed<I>::value> { \
428#undef INTEGER_FOR_DIGITS_AND_SIGN
434 "Max integer size not supported for this toolchain.");
449template <
typename Lhs,
457template <
typename Lhs,
typename Rhs>
462template <
typename Lhs,
typename Rhs>
468template <
typename Lhs,
484template <
typename Lhs,
typename Rhs>
489template <
typename Lhs,
typename Rhs>
498 bool is_intmax_type =
502 bool is_max_exponent =
512template <
typename Lhs,
typename Rhs,
bool is_
intmax_type>
515 static const bool is_contained =
true;
519template <
typename Lhs,
typename Rhs>
525 static const bool is_contained =
true;
529template <
typename Lhs,
typename Rhs>
532 static const bool is_contained =
false;
539template <
typename T,
typename Lhs,
typename Rhs = Lhs>
553template <
typename Lhs,
563template <
typename Lhs,
typename Rhs>
570 static const bool is_contained =
true;
573template <
typename Lhs,
typename Rhs>
576 static const bool is_contained =
false;
642template <
typename L,
typename R>
649template <
typename L,
typename R>
657template <
typename L,
typename R>
669template <
typename Src>
670constexpr typename std::make_signed<
674 "Argument must be a signed or unsigned integer type.");
681template <
typename Src>
682constexpr typename std::make_unsigned<
686 "Argument must be a signed or unsigned integer type.");
690template <
typename L,
typename R>
696 (l_range == r_range &&
static_cast<decltype(lhs + rhs)
>(lhs) <
697 static_cast<decltype(lhs + rhs)
>(rhs));
700template <
typename L,
typename R>
703 "Types must be numeric.");
704 static constexpr bool Test(
const L lhs,
const R rhs) {
705 return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
706 DstRangeRelationToSrcRange<L>(rhs));
710template <
typename L,
typename R>
716 (l_range == r_range &&
static_cast<decltype(lhs + rhs)
>(lhs) <=
717 static_cast<decltype(lhs + rhs)
>(rhs));
720template <
typename L,
typename R>
723 "Types must be numeric.");
724 static constexpr bool Test(
const L lhs,
const R rhs) {
726 DstRangeRelationToSrcRange<L>(rhs));
730template <
typename L,
typename R>
736 (l_range == r_range &&
static_cast<decltype(lhs + rhs)
>(lhs) >
737 static_cast<decltype(lhs + rhs)
>(rhs));
740template <
typename L,
typename R>
743 "Types must be numeric.");
744 static constexpr bool Test(
const L lhs,
const R rhs) {
745 return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
746 DstRangeRelationToSrcRange<L>(rhs));
750template <
typename L,
typename R>
756 (l_range == r_range &&
static_cast<decltype(lhs + rhs)
>(lhs) >=
757 static_cast<decltype(lhs + rhs)
>(rhs));
760template <
typename L,
typename R>
763 "Types must be numeric.");
764 static constexpr bool Test(
const L lhs,
const R rhs) {
766 DstRangeRelationToSrcRange<L>(rhs));
770template <
typename L,
typename R>
773 "Types must be numeric.");
774 static constexpr bool Test(
const L lhs,
const R rhs) {
775 return DstRangeRelationToSrcRange<R>(lhs) ==
776 DstRangeRelationToSrcRange<L>(rhs) &&
777 static_cast<decltype(lhs + rhs)
>(lhs) ==
778 static_cast<decltype(lhs + rhs)
>(rhs);
782template <
typename L,
typename R>
785 "Types must be numeric.");
786 static constexpr bool Test(
const L lhs,
const R rhs) {
787 return DstRangeRelationToSrcRange<R>(lhs) !=
788 DstRangeRelationToSrcRange<L>(rhs) ||
789 static_cast<decltype(lhs + rhs)
>(lhs) !=
790 static_cast<decltype(lhs + rhs)
>(rhs);
796template <
template <
typename,
typename>
class C,
typename L,
typename R>
799 "Types must be numeric.");
802 return Promotion::is_contained
805 static_cast<BigType
>(
static_cast<L>(lhs)),
806 static_cast<BigType
>(
static_cast<R>(rhs)))
811template <
typename Dst,
typename Src>
817template <
typename Dst,
typename Src>
820 std::numeric_limits<Src>::lowest());
823template <
typename Dst,
typename Src>
825 return !IsMaxInRangeForNumericType<Dst, Src>()
830template <
typename Dst,
typename Src>
832 return !IsMinInRangeForNumericType<Dst, Src>()
833 ? Dst(std::numeric_limits<Dst>::lowest())
834 : Dst(std::numeric_limits<Src>::lowest());
840template <
typename Dst,
typename Src = Dst>
842 return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
static bool is_integral(const SkRect &r)
constexpr bool IsOverflow() const
constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
constexpr bool IsValid() const
constexpr bool operator==(const RangeCheck rhs) const
constexpr bool IsInvalid() const
constexpr bool IsOverflowFlagSet() const
constexpr bool IsUnderflowFlagSet() const
constexpr bool IsUnderflow() const
constexpr bool operator!=(const RangeCheck rhs) const
static float max(float r, float g, float b)
static bool is_signed(const Type &type)
constexpr Dst CommonMin()
constexpr bool IsMinInRangeForNumericType()
ArithmeticPromotionCategory
constexpr bool IsLessOrEqualImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr bool IsGreaterOrEqualImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
NumericRangeRepresentation
@ NUMERIC_RANGE_NOT_CONTAINED
@ NUMERIC_RANGE_CONTAINED
constexpr bool IsValueNegative(T value)
constexpr std::make_unsigned< T >::type SafeUnsignedAbs(T value)
constexpr bool SafeCompare(const L lhs, const R rhs)
constexpr std::make_signed< typenamebase::internal::UnderlyingType< Src >::type >::type as_signed(const Src value)
constexpr std::make_unsigned< typenamebase::internal::UnderlyingType< Src >::type >::type as_unsigned(const Src value)
constexpr std::make_signed< T >::type ConditionalNegate(T x, bool is_negative)
constexpr bool IsCompileTimeConstant(const T)
@ INTEGER_REPRESENTATION_UNSIGNED
@ INTEGER_REPRESENTATION_SIGNED
INTEGER_FOR_DIGITS_AND_SIGN(int8_t)
constexpr bool IsMaxInRangeForNumericType()
constexpr Dst CommonMaxOrMin(bool is_min)
constexpr RangeCheck DstRangeRelationToSrcRange(Src value)
constexpr bool IsLessImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr bool IsGreaterImpl(const L lhs, const R rhs, const RangeCheck l_range, const RangeCheck r_range)
constexpr bool MustTreatAsConstexpr(const T v)
constexpr Dst CommonMax()
constexpr bool CanDetectCompileTimeConstant()
typename std::underlying_type< T >::type type
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)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr bool Test(const L lhs, const R rhs)
static constexpr T Adjust(T value)
static constexpr Dst lowest()
std::numeric_limits< Src > SrcLimits
static constexpr Dst max()
typename std::numeric_limits< Dst > DstLimits
static const size_t value
typename IntegerForDigitsAndSign< IntegerBitsPlusSign< Integer >::value *2, IsSigned >::type type
typename ArithmeticOrUnderlyingEnum< T >::type type
static const bool is_numeric
static const bool is_strict
static const bool is_checked
static const bool is_clamped