16namespace CppClingo::Util {
24template <std::
signed_
integral T, std::
signed_
integral S>
auto check_cast(S in) ->
bool {
25 return std::in_range<T>(std::move(in));
29template <std::
integral T, std::
integral S>
auto safe_cast(S in) -> T {
30 if (std::in_range<T, S>(in)) {
31 return static_cast<T
>(std::move(in));
33 throw std::range_error(
"invalid cast");
41template <std::
signed_
integral S>
auto check_add(S a, S b) -> std::optional<S> {
43 if (S c; !__builtin_add_overflow(a, b, &c)) {
48 if constexpr (std::is_same_v<S, int32_t>) {
49 int64_t tmp =
static_cast<int64_t
>(a) + b;
50 if (check_cast<int32_t>(tmp)) {
51 return static_cast<int32_t
>(tmp);
55 using U = std::make_unsigned_t<S>;
56 S tmp =
static_cast<S
>(
static_cast<U
>(a) +
static_cast<U
>(b));
57 if ((a >= 0 && b >= 0 && tmp < a) || (a < 0 && b < 0 && tmp > a)) {
70template <std::
signed_
integral S>
auto check_sub(S a, S b) -> std::optional<S> {
72 if (S c; !__builtin_sub_overflow(a, b, &c)) {
77 if constexpr (std::is_same_v<S, int32_t>) {
78 int64_t tmp =
static_cast<int64_t
>(a) - b;
79 if (check_cast<int32_t>(tmp)) {
80 return static_cast<int32_t
>(tmp);
84 using U = std::make_unsigned_t<S>;
85 S tmp =
static_cast<S
>(
static_cast<U
>(a) -
static_cast<U
>(b));
86 if ((a >= 0 && b < 0 && tmp < a) || (b >= 0 && tmp > a)) {
97template <std::
signed_
integral S>
auto check_neg(S a) -> std::optional<S> {
98 if (a == std::numeric_limits<S>::min()) {
107template <std::
signed_
integral S>
auto check_abs(S a) -> std::optional<S> {
108 if (a == std::numeric_limits<S>::min()) {
111 return a < 0 ? -a : a;
119template <std::
signed_
integral S>
auto check_mul(S a, S b) -> std::optional<S> {
121 if (S c; !__builtin_mul_overflow(a, b, &c)) {
126 if constexpr (std::is_same_v<S, int32_t>) {
127 int64_t tmp =
static_cast<int64_t
>(a) * b;
128 if (check_cast<int32_t>(tmp)) {
129 return static_cast<int32_t
>(tmp);
133 if (a > 0 && b > 0 && a > std::numeric_limits<S>::max() / b) {
136 if (a > 0 && b < 0 && b < std::numeric_limits<S>::min() / a) {
139 if (a < 0 && b > 0 && a < std::numeric_limits<S>::min() / b) {
142 if (a < 0 && b < 0 && b < std::numeric_limits<S>::max() / a) {
153template <std::
signed_
integral S>
auto check_div(S a, S b) -> std::optional<S> {
154 if (b == 0 || (b == -1 && a == std::numeric_limits<S>::min())) {
160 if ((r > 0 && b < 0) || (r < 0 && b > 0)) {
169template <std::
signed_
integral S>
auto check_mod(S a, S b) -> std::optional<S> {
178 if ((r > 0 && b < 0) || (r < 0 && b > 0)) {
189template <std::
signed_
integral S>
auto check_pow(S a, S b) -> std::optional<S> {
197 if (!tmp.has_value()) {
205 if (!tmp.has_value()) {
auto check_neg(S a) -> std::optional< S >
Negate an integer checking overflows.
Definition checked_math.hh:97
auto check_pow(S a, S b) -> std::optional< S >
Power of the given integers checking overflows.
Definition checked_math.hh:189
auto check_mul(S a, S b) -> std::optional< S >
Multiply two integers checking overflows.
Definition checked_math.hh:119
auto safe_cast(S in) -> T
Cast S to T if possible.
Definition checked_math.hh:29
auto check_mod(S a, S b) -> std::optional< S >
Modulo of two integers checking overflows (truncating toward negative infinity).
Definition checked_math.hh:169
auto check_sub(S a, S b) -> std::optional< S >
Subtract two integers checking overflows.
Definition checked_math.hh:70
auto check_abs(S a) -> std::optional< S >
The absolute of an integer checking overflows.
Definition checked_math.hh:107
auto check_div(S a, S b) -> std::optional< S >
Divide two integers checking overflows (truncating toward negative infinity).
Definition checked_math.hh:153
auto check_add(S a, S b) -> std::optional< S >
Add two integers checking overflows.
Definition checked_math.hh:41
auto check_cast(S in) -> bool
Check if s of type S can be casted to T without loss.
Definition checked_math.hh:24