10 #ifndef OVERFLOWSAFE_TYPE_HPP
11 #define OVERFLOWSAFE_TYPE_HPP
17 # if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_sub_overflow) && __has_builtin(__builtin_mul_overflow)
18 # define HAS_OVERFLOW_BUILTINS
32 static constexpr T T_MAX = std::numeric_limits<T>::max();
33 static constexpr T T_MIN = std::numeric_limits<T>::min();
44 inline constexpr
OverflowSafeInt& operator = (T other) { this->m_value = other;
return *
this; }
55 #ifdef HAS_OVERFLOW_BUILTINS
56 if (__builtin_add_overflow(this->m_value, other.
m_value, &this->m_value)) [[unlikely]] {
57 this->m_value = (other.
m_value < 0) ? T_MIN : T_MAX;
61 this->m_value = T_MAX;
62 }
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)))) {
63 this->m_value = T_MIN;
78 #ifdef HAS_OVERFLOW_BUILTINS
79 if (__builtin_sub_overflow(this->m_value, other.
m_value, &this->m_value)) [[unlikely]] {
80 this->m_value = (other.
m_value < 0) ? T_MAX : T_MIN;
84 this->m_value = T_MAX;
85 }
else if (this->m_value < 0 && other.m_value > 0 && (T_MAX + this->m_value) < (T_MIN + T_MAX) + other.
m_value) {
86 this->m_value = T_MIN;
102 inline constexpr
OverflowSafeInt& operator ++ () {
return *
this += 1; }
103 inline constexpr
OverflowSafeInt& operator -- () {
return *
this += -1; }
115 #ifdef HAS_OVERFLOW_BUILTINS
116 const bool is_result_positive = (this->m_value < 0) == (factor < 0);
117 if (__builtin_mul_overflow(this->m_value, factor, &this->m_value)) [[unlikely]] {
118 this->m_value = is_result_positive ? T_MAX : T_MIN;
122 this->m_value = (this->m_value == T_MIN) ? T_MAX : -this->m_value;
123 }
else if (factor > 0 && this->m_value > 0 && (T_MAX / factor) < this->
m_value) {
124 this->m_value = T_MAX;
125 }
else if (factor > 0 && this->m_value < 0 && (T_MIN / factor) > this->
m_value) {
126 this->m_value = T_MIN;
127 }
else if (factor < 0 && this->
m_value > 0 && (T_MIN / factor) < this->
m_value) {
128 this->m_value = T_MIN;
129 }
else if (factor < 0 && this->
m_value < 0 && (T_MAX / factor) > this->
m_value) {
130 this->m_value = T_MAX;
132 this->m_value *= factor;
140 inline constexpr
OverflowSafeInt operator * (
const int factor)
const {
OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
141 inline constexpr
OverflowSafeInt operator * (
const uint factor)
const {
OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
142 inline constexpr
OverflowSafeInt operator * (
const uint16_t factor)
const {
OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
143 inline constexpr
OverflowSafeInt operator * (
const uint8_t factor)
const {
OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
146 inline constexpr
OverflowSafeInt& operator /= (
const int64_t divisor) { this->m_value /= divisor;
return *
this; }
152 inline constexpr
OverflowSafeInt& operator %= (
const int divisor) { this->m_value %= divisor;
return *
this; }
156 inline constexpr
OverflowSafeInt& operator <<= (
const int shift) { this->m_value <<= shift;
return *
this; }
158 inline constexpr
OverflowSafeInt& operator >>= (
const int shift) { this->m_value >>= shift;
return *
this; }
162 inline constexpr
bool operator == (
const OverflowSafeInt& other)
const {
return this->m_value == other.
m_value; }
163 inline constexpr
bool operator != (
const OverflowSafeInt& other)
const {
return !(*
this == other); }
164 inline constexpr
bool operator > (
const OverflowSafeInt& other)
const {
return this->m_value > other.
m_value; }
165 inline constexpr
bool operator >= (
const OverflowSafeInt& other)
const {
return this->m_value >= other.
m_value; }
166 inline constexpr
bool operator < (
const OverflowSafeInt& other)
const {
return !(*
this >= other); }
167 inline constexpr
bool operator <= (
const OverflowSafeInt& other)
const {
return !(*
this > other); }
170 inline constexpr
bool operator == (
const int other)
const {
return this->m_value == other; }
171 inline constexpr
bool operator != (
const int other)
const {
return !(*
this == other); }
172 inline constexpr
bool operator > (
const int other)
const {
return this->m_value > other; }
173 inline constexpr
bool operator >= (
const int other)
const {
return this->m_value >= other; }
174 inline constexpr
bool operator < (
const int other)
const {
return !(*
this >= other); }
175 inline constexpr
bool operator <= (
const int other)
const {
return !(*
this > other); }
177 inline constexpr
operator T ()
const {
return this->
m_value; }
218 template <
typename To,
typename From>
221 #undef HAS_OVERFLOW_BUILTINS
Overflow safe template for integers, i.e.
constexpr OverflowSafeInt & operator+=(const OverflowSafeInt &other)
Safe implementation of addition.
constexpr OverflowSafeInt & operator*=(const int factor)
Safe implementation of multiplication.
constexpr OverflowSafeInt & operator-=(const OverflowSafeInt &other)
Safe implementation of subtraction.
T m_value
The non-overflow safe backend to store the value in.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.