32 static constexpr T T_MAX = std::numeric_limits<T>::max();
33 static constexpr T T_MIN = std::numeric_limits<T>::min();
40 constexpr OverflowSafeInt() :
m_value(0) { }
43 constexpr OverflowSafeInt(
const T int_) :
m_value(int_) { }
45 inline constexpr OverflowSafeInt& operator = (
const OverflowSafeInt& other) { this->
m_value = other.
m_value;
return *
this; }
46 inline constexpr OverflowSafeInt& operator = (T other) { this->
m_value = other;
return *
this; }
48 inline constexpr OverflowSafeInt operator - ()
const {
return OverflowSafeInt(this->
m_value == T_MIN ? T_MAX : -this->
m_value); }
56 inline constexpr OverflowSafeInt&
operator += (
const OverflowSafeInt& other)
58#ifdef HAS_OVERFLOW_BUILTINS
59 if (__builtin_add_overflow(this->m_value, other.
m_value, &this->m_value)) [[unlikely]] {
60 this->m_value = (other.
m_value < 0) ? T_MIN : T_MAX;
63 if (this->m_value > 0 && other.
m_value > 0 && (T_MAX - other.
m_value) < this->m_value) {
64 this->m_value = T_MAX;
65 }
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)))) {
66 this->m_value = T_MIN;
80 inline constexpr OverflowSafeInt&
operator -= (
const OverflowSafeInt& other)
82#ifdef HAS_OVERFLOW_BUILTINS
83 if (__builtin_sub_overflow(this->m_value, other.
m_value, &this->m_value)) [[unlikely]] {
84 this->m_value = (other.
m_value < 0) ? T_MAX : T_MIN;
87 if (this->m_value > 0 && other.
m_value < 0 && (T_MAX + other.
m_value) < this->m_value) {
88 this->m_value = T_MAX;
90 this->m_value = T_MIN;
100 inline constexpr OverflowSafeInt operator + (
const int other)
const { OverflowSafeInt result = *
this; result += (int64_t)other;
return result; }
101 inline constexpr OverflowSafeInt operator + (
const uint other)
const { OverflowSafeInt result = *
this; result += (int64_t)other;
return result; }
102 inline constexpr OverflowSafeInt operator - (
const OverflowSafeInt& other)
const { OverflowSafeInt result = *
this; result -= other;
return result; }
103 inline constexpr OverflowSafeInt operator - (
const int other)
const { OverflowSafeInt result = *
this; result -= (int64_t)other;
return result; }
104 inline constexpr OverflowSafeInt operator - (
const uint other)
const { OverflowSafeInt result = *
this; result -= (int64_t)other;
return result; }
106 inline constexpr OverflowSafeInt& operator ++ () {
return *
this += 1; }
107 inline constexpr OverflowSafeInt& operator -- () {
return *
this += -1; }
108 inline constexpr OverflowSafeInt operator ++ (
int) { OverflowSafeInt org = *
this; *
this += 1;
return org; }
109 inline constexpr OverflowSafeInt operator -- (
int) { OverflowSafeInt org = *
this; *
this += -1;
return org; }
120#ifdef HAS_OVERFLOW_BUILTINS
121 const bool is_result_positive = (this->m_value < 0) == (factor < 0);
122 if (__builtin_mul_overflow(this->m_value, factor, &this->m_value)) [[unlikely]] {
123 this->m_value = is_result_positive ? T_MAX : T_MIN;
127 this->m_value = (this->m_value == T_MIN) ? T_MAX : -this->m_value;
128 }
else if (factor > 0 && this->m_value > 0 && (T_MAX / factor) < this->m_value) {
129 this->m_value = T_MAX;
130 }
else if (factor > 0 && this->m_value < 0 && (T_MIN / factor) > this->m_value) {
131 this->m_value = T_MIN;
132 }
else if (factor < 0 && this->
m_value > 0 && (T_MIN / factor) < this->m_value) {
133 this->m_value = T_MIN;
134 }
else if (factor < 0 && this->
m_value < 0 && (T_MAX / factor) > this->m_value) {
135 this->m_value = T_MAX;
137 this->m_value *= factor;
145 inline constexpr OverflowSafeInt operator * (
const int factor)
const { OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
146 inline constexpr OverflowSafeInt operator * (
const uint factor)
const { OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
147 inline constexpr OverflowSafeInt operator * (
const uint16_t factor)
const { OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
148 inline constexpr OverflowSafeInt operator * (
const uint8_t factor)
const { OverflowSafeInt result = *
this; result *= (int64_t)factor;
return result; }
151 inline constexpr OverflowSafeInt& operator /= (
const int64_t divisor) { this->
m_value /= divisor;
return *
this; }
152 inline constexpr OverflowSafeInt operator / (
const OverflowSafeInt& divisor)
const { OverflowSafeInt result = *
this; result /= divisor.
m_value;
return result; }
153 inline constexpr OverflowSafeInt operator / (
const int divisor)
const { OverflowSafeInt result = *
this; result /= divisor;
return result; }
154 inline constexpr OverflowSafeInt operator / (
const uint divisor)
const { OverflowSafeInt result = *
this; result /= (int)divisor;
return result; }
157 inline constexpr OverflowSafeInt& operator %= (
const int divisor) { this->
m_value %= divisor;
return *
this; }
158 inline constexpr OverflowSafeInt operator % (
const int divisor)
const { OverflowSafeInt result = *
this; result %= divisor;
return result; }
161 inline constexpr OverflowSafeInt& operator <<= (
const int shift) { this->
m_value <<= shift;
return *
this; }
162 inline constexpr OverflowSafeInt operator << (
const int shift)
const { OverflowSafeInt result = *
this; result <<= shift;
return result; }
163 inline constexpr OverflowSafeInt& operator >>= (
const int shift) { this->
m_value >>= shift;
return *
this; }
164 inline constexpr OverflowSafeInt operator >> (
const int shift)
const { OverflowSafeInt result = *
this; result >>= shift;
return result; }
167 inline constexpr bool operator == (
const OverflowSafeInt& other)
const {
return this->
m_value == other.
m_value; }
168 inline constexpr auto operator <=>(
const OverflowSafeInt& other)
const {
return this->
m_value <=> other.
m_value; }
171 inline constexpr bool operator == (
const int other)
const {
return this->
m_value == other; }
172 inline constexpr auto operator <=>(
const int other)
const {
return this->
m_value <=> other; }
174 inline constexpr operator T ()
const {
return this->
m_value; }
176 static inline constexpr OverflowSafeInt<T> max() {
return T_MAX; }
177 static inline constexpr OverflowSafeInt<T> min() {
return T_MIN; }
179 BaseType base() const noexcept {
return this->
m_value; }