6#include "TTauri/Foundation/required.hpp"
7#include "TTauri/Foundation/os_detect.hpp"
8#include "TTauri/Foundation/type_traits.hpp"
12#if TT_PROCESSOR == TT_CPU_X64
16#if TT_OPERATING_SYSTEM == TT_OS_WINDOWS
18#pragma intrinsic(_mul128)
23template<
typename T,
typename U>
24inline bool convert_overflow(T x, U *r)
26 static_assert(std::is_integral_v<U>,
"convert_overflow() requires integral return type.");
27 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"convert_overflow() requires float or integral argument type.");
29 if constexpr (std::is_integral_v<T>) {
31 *r =
static_cast<U
>(x);
40inline bool add_overflow(T lhs, T rhs, T *r)
42 static_assert(std::is_integral_v<T>,
"add_overflow() requires integral arguments.");
44 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
46 return __builtin_add_overflow(lhs, rhs, r);
48 }
else if constexpr (std::is_unsigned_v<T>) {
55 ttlet lhs_ =
static_cast<std::make_unsigned_t<T>
>(lhs);
56 ttlet rhs_ =
static_cast<std::make_unsigned_t<T>
>(rhs);
57 ttlet r_ = lhs_ + rhs_;
58 *r =
static_cast<T
>(r_);
59 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
64inline bool sub_overflow(T lhs, T rhs, T *r)
66 static_assert(std::is_integral_v<T>,
"sub_overflow() requires integral arguments.");
68 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
70 return __builtin_sub_overflow(lhs, rhs, r);
72 }
else if constexpr (std::is_unsigned_v<T>) {
79 ttlet lhs_ =
static_cast<std::make_unsigned_t<T>
>(lhs);
80 ttlet rhs_ =
static_cast<std::make_unsigned_t<T>
>(rhs);
81 ttlet r_ = lhs_ - rhs_;
82 *r =
static_cast<T
>(r_);
83 return ((lhs ^ rhs) & (~rhs ^ *r)) < 0;
91inline bool mul_overflow(T lhs, T rhs, T *r)
93 static_assert(std::is_integral_v<T>,
"mul_overflow() requires integral arguments.");
95 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
96 return __builtin_mul_overflow(lhs, rhs, r);
98 }
else if constexpr (std::is_signed_v<T> && Compiler::current == Compiler::MSVC &&
sizeof(T) ==
sizeof(
long long)) {
101 *r = _mul128(lhs, rhs, &hi);
104 return (hi ^ (*r >> 63)) != 0;
106 }
else if constexpr (std::is_unsigned_v<T> && Compiler::current == Compiler::MSVC &&
sizeof(T) ==
sizeof(
unsigned long long)) {
107 unsigned long long hi = 0;
108 *r = _umul128(lhs, rhs, &hi);
111 }
else if constexpr (
sizeof(T) <= (
sizeof(make_intmax_t<T>)/2)) {
113 ttlet lhs_ =
static_cast<make_intmax_t<T>
>(lhs);
114 ttlet rhs_ =
static_cast<make_intmax_t<T>
>(rhs);
115 ttlet r_ = lhs_ * rhs_;
116 *r =
static_cast<T
>(r_);