15#if HI_PROCESSOR == HI_CPU_X64
19#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
21#pragma intrinsic(_mul128)
24namespace hi::inline v1 {
26template<
typename T,
typename U>
27inline bool convert_overflow(T x, U *r)
29 static_assert(std::is_integral_v<U>,
"convert_overflow() requires integral return type.");
31 std::is_integral_v<T> || std::is_floating_point_v<T>,
"convert_overflow() requires float or integral argument type.");
33 if constexpr (std::is_integral_v<T>) {
35 *r =
static_cast<U
>(x);
44inline bool add_overflow(T lhs, T rhs, T *r)
46 static_assert(std::is_integral_v<T>,
"add_overflow() requires integral arguments.");
48 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
50 return __builtin_add_overflow(lhs, rhs, r);
52 }
else if constexpr (std::is_unsigned_v<T>) {
59 hilet lhs_ =
static_cast<std::make_unsigned_t<T>
>(lhs);
60 hilet rhs_ =
static_cast<std::make_unsigned_t<T>
>(rhs);
61 hilet r_ = lhs_ + rhs_;
62 *r =
static_cast<T
>(r_);
63 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
68inline bool sub_overflow(T lhs, T rhs, T *r)
70 static_assert(std::is_integral_v<T>,
"sub_overflow() requires integral arguments.");
72 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
74 return __builtin_sub_overflow(lhs, rhs, r);
76 }
else if constexpr (std::is_unsigned_v<T>) {
83 hilet lhs_ =
static_cast<std::make_unsigned_t<T>
>(lhs);
84 hilet rhs_ =
static_cast<std::make_unsigned_t<T>
>(rhs);
85 hilet r_ = lhs_ - rhs_;
86 *r =
static_cast<T
>(r_);
87 return ((lhs ^ rhs) & (~rhs ^ *r)) < 0;
95inline bool mul_overflow(T lhs, T rhs, T *r)
97 static_assert(std::is_integral_v<T>,
"mul_overflow() requires integral arguments.");
99 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
100 return __builtin_mul_overflow(lhs, rhs, r);
102 }
else if constexpr (std::is_signed_v<T> && compiler::current == compiler::msvc &&
sizeof(T) ==
sizeof(
long long)) {
105 *r = _mul128(lhs, rhs, &hi);
108 return (hi ^ (*r >> 63)) != 0;
110 }
else if constexpr (
111 std::is_unsigned_v<T> && compiler::current == compiler::msvc &&
sizeof(T) ==
sizeof(
unsigned long long)) {
112 unsigned long long hi = 0;
113 *r = _umul128(lhs, rhs, &hi);
116 }
else if constexpr (
sizeof(T) <= (
sizeof(make_intmax_t<T>) / 2)) {
118 hilet lhs_ =
static_cast<make_intmax_t<T>
>(lhs);
119 hilet rhs_ =
static_cast<make_intmax_t<T>
>(rhs);
120 hilet r_ = lhs_ * rhs_;
121 *r =
static_cast<T
>(r_);
125 hi_not_implemented();
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...