mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Use GCC/clang builtins for overflow safety when supported
This commit is contained in:
parent
3d0d9edafd
commit
e6e2a67aa1
|
@ -12,6 +12,12 @@
|
|||
|
||||
#include "math_func.hpp"
|
||||
|
||||
#ifdef __has_builtin
|
||||
# if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_sub_overflow) && __has_builtin(__builtin_mul_overflow)
|
||||
# define HAS_OVERFLOW_BUILTINS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Overflow safe template for integers, i.e. integers that will never overflow
|
||||
* you multiply the maximum value with 2, or add 2, or subtract something from
|
||||
|
@ -43,6 +49,11 @@ public:
|
|||
*/
|
||||
inline OverflowSafeInt& operator += (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (unlikely(__builtin_add_overflow(this->m_value, other.m_value, &this->m_value))) {
|
||||
this->m_value = (other.m_value < 0) ? T_MIN : T_MAX;
|
||||
}
|
||||
#else
|
||||
if (this->m_value > 0 && other.m_value > 0 && (T_MAX - other.m_value) < this->m_value) {
|
||||
this->m_value = T_MAX;
|
||||
} else if (this->m_value < 0 && other.m_value < 0 && (this->m_value == T_MIN || other.m_value == T_MIN || ((T_MAX + this->m_value) + other.m_value < (T_MIN + T_MAX)))) {
|
||||
|
@ -50,6 +61,7 @@ public:
|
|||
} else {
|
||||
this->m_value += other.m_value;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -60,6 +72,11 @@ public:
|
|||
*/
|
||||
inline OverflowSafeInt& operator -= (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (unlikely(__builtin_sub_overflow(this->m_value, other.m_value, &this->m_value))) {
|
||||
this->m_value = (other.m_value < 0) ? T_MAX : T_MIN;
|
||||
}
|
||||
#else
|
||||
if (this->m_value > 0 && other.m_value < 0 && (T_MAX + other.m_value) < this->m_value) {
|
||||
this->m_value = T_MAX;
|
||||
} else if (this->m_value < 0 && other.m_value > 0 && (T_MAX + this->m_value) < (T_MIN + T_MAX) + other.m_value) {
|
||||
|
@ -67,6 +84,7 @@ public:
|
|||
} else {
|
||||
this->m_value -= other.m_value;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -91,6 +109,12 @@ public:
|
|||
*/
|
||||
inline OverflowSafeInt& operator *= (const int factor)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
bool is_result_positive = (this->m_value < 0) == (factor < 0); // -ve * -ve == +ve
|
||||
if (unlikely(__builtin_mul_overflow(this->m_value, factor, &this->m_value))) {
|
||||
this->m_value = is_result_positive ? T_MAX : T_MIN;
|
||||
}
|
||||
#else
|
||||
if (factor == -1) {
|
||||
this->m_value = (this->m_value == T_MIN) ? T_MAX : -this->m_value;
|
||||
} else if (factor > 0 && this->m_value > 0 && (T_MAX / factor) < this->m_value) {
|
||||
|
@ -104,6 +128,7 @@ public:
|
|||
} else {
|
||||
this->m_value *= factor;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -176,4 +201,6 @@ template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_
|
|||
typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64;
|
||||
typedef OverflowSafeInt<int32, INT32_MAX, INT32_MIN> OverflowSafeInt32;
|
||||
|
||||
#undef HAS_OVERFLOW_BUILTINS
|
||||
|
||||
#endif /* OVERFLOWSAFE_TYPE_HPP */
|
||||
|
|
Loading…
Reference in New Issue