Loading...
Searching...
No Matches
safe_op.hpp
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef SAFE_OP_HPP_
#define SAFE_OP_HPP_
#include <limits>
#include <stdexcept>
#include <type_traits>
#ifdef _MSC_VER
#include <Intsafe.h>
#endif
namespace Safe {
namespace Internal {
template <typename T>
bool fallback_add_overflow(T summand_1, T summand_2, T& result) {
if constexpr (std::is_signed_v<T> && sizeof(T) >= sizeof(int)) {
if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2)))
return true;
result = summand_1 + summand_2;
return false;
} else if constexpr (std::is_signed_v<T> && sizeof(T) < sizeof(int)) {
const int res = summand_1 + summand_2;
if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
return true;
}
result = static_cast<T>(res);
return false;
} else {
result = summand_1 + summand_2;
return result < summand_1;
}
}
template <typename T>
bool builtin_add_overflow(T summand_1, T summand_2, T& result) {
return fallback_add_overflow(summand_1, summand_2, result);
}
#if defined(__GNUC__) || defined(__clang__)
#if __GNUC__ >= 5 || __clang_major__ >= 3
#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
/* Full specialization of builtin_add_overflow for type using the */ \
/* builtin_name intrinsic */ \
template <> \
constexpr bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) { \
return builtin_name(summand_1, summand_2, &result); \
}
SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
#undef SPECIALIZE_builtin_add_overflow
#endif // __GNUC__ >= 5 || __clang_major >= 3
#endif
} // namespace Internal
template <typename T>
T add(T summand_1, T summand_2) {
T res = 0;
if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
throw std::overflow_error("Overflow in addition");
}
return res;
}
template <typename T>
T abs(T num) noexcept {
if constexpr (std::is_signed_v<T>) {
if (num == std::numeric_limits<T>::min())
return std::numeric_limits<T>::max();
return num < 0 ? -num : num;
}
return num;
}
} // namespace Safe
#endif // SAFE_OP_HPP_
Safe::Internal::builtin_add_overflow
bool builtin_add_overflow(T summand_1, T summand_2, T &result)
Overflow addition check using compiler intrinsics.
Definition safe_op.hpp:96
Safe::Internal::fallback_add_overflow
bool fallback_add_overflow(T summand_1, T summand_2, T &result)
Check the addition of two numbers for overflows for signed integer types larger than int or with the ...
Definition safe_op.hpp:62
Safe
Arithmetic operations with overflow checks.
Definition safe_op.hpp:17
Safe::add
T add(T summand_1, T summand_2)
Safe addition, throws an exception on overflow.
Definition safe_op.hpp:157
Safe::abs
T abs(T num) noexcept
Calculates the absolute value of a number without producing negative values.
Definition safe_op.hpp:188