7#include "utility/module.hpp"
12#if HI_PROCESSOR == HI_CPU_X64
16#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
18#pragma intrinsic(_mul128)
21namespace hi::inline
v1 {
24template<
typename T,
typename U>
25inline bool convert_overflow(T x, U *r)
27 static_assert(std::is_integral_v<U>,
"convert_overflow() requires integral return type.");
29 std::is_integral_v<T> || std::is_floating_point_v<T>,
"convert_overflow() requires float or integral argument type.");
31 if constexpr (std::is_integral_v<T>) {
33 *r =
static_cast<U
>(x);
41template<std::
integral T>
42constexpr bool overflow_add(T lhs, T rhs, T *r)
noexcept
44 if (not std::is_constant_evaluated()) {
45#if HI_COMPILER == HI_CC_GCC || HI_COMPPILER == HI_CC_CLANG
47 return __builtin_add_overflow(lhs, rhs, r);
52 hilet lhs_ =
static_cast<std::make_unsigned_t<T>
>(lhs);
53 hilet rhs_ =
static_cast<std::make_unsigned_t<T>
>(rhs);
54 hilet r_ = lhs_ + rhs_;
55 *r =
static_cast<T
>(r_);
63 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
66template<std::
integral T>
67constexpr bool sub_overflow(T lhs, T rhs, T *r)
69 if (not std::constant_evaluated()) {
70#if HI_COMPILER == HI_CC_GCC || HI_COMPPILER == HI_CC_CLANG
72 return __builtin_sub_overflow(lhs, rhs, r);
76 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;
94template<std::
unsigned_
integral T>
97 if (not std::constant_evaluated()) {
98#if HI_COMPILER == HI_CC_GCC || HI_COMPILER == HI_CC_CLANG
100 return __builtin_mul_overflow(lhs, rhs, r);
102#elif HI_COMPILER == HI_CC_MSVC
103 if constexpr (std::is_same_v<T, uint64_t>) {
104 auto hi = uint64_t{};
105 *r = _umul128(lhs, rhs, &
hi);
111 if constexpr (
sizeof(T) <
sizeof(
unsigned long long)) {
112 hilet lhs_ =
static_cast<unsigned long long>(lhs);
113 hilet rhs_ =
static_cast<unsigned long long>(rhs);
114 auto r_ = lhs_ * rhs_;
115 *r =
static_cast<T
>(r_);
116 r_ >>=
sizeof(T) * CHAR_BIT;
121 constexpr auto max_width =
sizeof(T) * CHAR_BIT;
122 hilet width = std::bit_width(lhs) + std::bit_width(rhs);
132template<std::
signed_
integral T>
133constexpr bool mul_overflow(T lhs, T rhs, T *r)
noexcept
135 if (not std::constant_evaluated()) {
136#if HI_COMPILER == HI_CC_GCC || HI_COMPILER == HI_CC_CLANG
138 return __builtin_mul_overflow(lhs, rhs, r);
140#elif HI_COMPILER == HI_CC_MSVC
141 if constexpr (std::is_same_v<T, int64_t>) {
144 *r = _mul128(lhs, rhs, &
hi);
147 return (
hi ^ (*r >> 63)) != 0;
152 if constexpr (
sizeof(T) <
sizeof(
long long)) {
153 hilet lhs_ =
static_cast<long long>(lhs);
154 hilet rhs_ =
static_cast<long long>(rhs);
155 auto r_ = lhs_ * rhs_;
156 *r =
static_cast<T
>(r_);
157 r_ >>=
sizeof(T) * CHAR_BIT - 1;
160 return static_cast<unsigned long long>(r_) > 1;
163 auto lhs_u =
static_cast<unsigned long long>(lhs);
164 auto rhs_u =
static_cast<unsigned long long>(rhs);
167 if (lhs == 0 or rhs == 0) {
170 }
else if (lhs_s == 1) {
173 }
else if (rhs_s == 1) {
179 auto lhs_a = lhs >= 0 ? lhs : -lhs;
180 auto rhs_a = rhs >= 0 ? rhs : -rhs;
181 auto width = std::bit_width(lhs_a) + std::bit_width(rhs_a);
184 if (res_bits > value_bit or ((res_bits == value_bit and lhs_a > unsigned_int_max / rhs_a)) {
186 return {(lhs_s >= 0) == (rhs_s >= 0) ? int_max : int_min};
189 *r = {lhs_s * rhs_s};
194template<std::
integral T>
195constexpr bool overflow_div(T lhs, T rhs, T *r)
197 if constexpr (std::is_signed_v<T>) {
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr bool mul_overflow(T lhs, T rhs, T *r) noexcept
Multiply with overflow detection.
Definition int_overflow.hpp:95
geometry/margins.hpp
Definition cache.hpp:11