17namespace CppClingo::Util {
25template <std::
signed_
integral T, std::
signed_
integral S>
auto check_cast(S in) ->
bool {
26 return std::in_range<T>(std::move(in));
30template <std::
integral T, std::
integral S>
auto safe_cast(S in) -> T {
31 if (std::in_range<T, S>(in)) {
32 return static_cast<T
>(std::move(in));
34 throw std::range_error(
"invalid cast");
42template <std::
signed_
integral S>
auto check_add(S a, S b) -> std::optional<S> {
44 if (S c; !__builtin_add_overflow(a, b, &c)) {
49 if constexpr (std::is_same_v<S, int32_t>) {
50 int64_t tmp =
static_cast<int64_t
>(a) + b;
51 if (check_cast<int32_t>(tmp)) {
52 return static_cast<int32_t
>(tmp);
56 using U = std::make_unsigned_t<S>;
57 S tmp =
static_cast<S
>(
static_cast<U
>(a) +
static_cast<U
>(b));
58 if ((a >= 0 && b >= 0 && tmp < a) || (a < 0 && b < 0 && tmp > a)) {
71template <std::
signed_
integral S>
auto check_sub(S a, S b) -> std::optional<S> {
73 if (S c; !__builtin_sub_overflow(a, b, &c)) {
78 if constexpr (std::is_same_v<S, int32_t>) {
79 int64_t tmp =
static_cast<int64_t
>(a) - b;
80 if (check_cast<int32_t>(tmp)) {
81 return static_cast<int32_t
>(tmp);
85 using U = std::make_unsigned_t<S>;
86 S tmp =
static_cast<S
>(
static_cast<U
>(a) -
static_cast<U
>(b));
87 if ((a >= 0 && b < 0 && tmp < a) || (b >= 0 && tmp > a)) {
98template <std::
signed_
integral S>
auto check_neg(S a) -> std::optional<S> {
99 if (a == std::numeric_limits<S>::min()) {
108template <std::
signed_
integral S>
auto check_abs(S a) -> std::optional<S> {
109 if (a == std::numeric_limits<S>::min()) {
112 return a < 0 ? -a : a;
120template <std::
signed_
integral S>
auto check_mul(S a, S b) -> std::optional<S> {
122 if (S c; !__builtin_mul_overflow(a, b, &c)) {
127 if constexpr (std::is_same_v<S, int32_t>) {
128 int64_t tmp =
static_cast<int64_t
>(a) * b;
129 if (check_cast<int32_t>(tmp)) {
130 return static_cast<int32_t
>(tmp);
134 if (a > 0 && b > 0 && a > std::numeric_limits<S>::max() / b) {
137 if (a > 0 && b < 0 && b < std::numeric_limits<S>::min() / a) {
140 if (a < 0 && b > 0 && a < std::numeric_limits<S>::min() / b) {
143 if (a < 0 && b < 0 && b < std::numeric_limits<S>::max() / a) {
154template <std::
signed_
integral S>
auto check_div(S a, S b) -> std::optional<S> {
155 if (b == 0 || (b == -1 && a == std::numeric_limits<S>::min())) {
161 if ((r > 0 && b < 0) || (r < 0 && b > 0)) {
170template <std::
signed_
integral S>
auto check_mod(S a, S b) -> std::optional<S> {
179 if ((r > 0 && b < 0) || (r < 0 && b > 0)) {
190template <std::
signed_
integral S>
auto check_pow(S a, S b) -> std::optional<S> {
198 if (!tmp.has_value()) {
206 if (!tmp.has_value()) {
auto check_neg(S a) -> std::optional< S >
Negate an integer checking overflows.
Definition checked_math.hh:98
auto check_pow(S a, S b) -> std::optional< S >
Power of the given integers checking overflows.
Definition checked_math.hh:190
auto check_mul(S a, S b) -> std::optional< S >
Multiply two integers checking overflows.
Definition checked_math.hh:120
auto safe_cast(S in) -> T
Cast S to T if possible.
Definition checked_math.hh:30
auto check_mod(S a, S b) -> std::optional< S >
Modulo of two integers checking overflows (truncating toward negative infinity).
Definition checked_math.hh:170
auto check_sub(S a, S b) -> std::optional< S >
Subtract two integers checking overflows.
Definition checked_math.hh:71
auto check_abs(S a) -> std::optional< S >
The absolute of an integer checking overflows.
Definition checked_math.hh:108
auto check_div(S a, S b) -> std::optional< S >
Divide two integers checking overflows (truncating toward negative infinity).
Definition checked_math.hh:154
auto check_add(S a, S b) -> std::optional< S >
Add two integers checking overflows.
Definition checked_math.hh:42
auto check_cast(S in) -> bool
Check if s of type S can be casted to T without loss.
Definition checked_math.hh:25