6#include "TTauri/Foundation/int_overflow.hpp"
7#include "TTauri/Foundation/type_traits.hpp"
8#include "TTauri/Foundation/exceptions.hpp"
15enum class on_overflow_t {
29constexpr on_overflow_t operator|(on_overflow_t lhs, on_overflow_t rhs)
noexcept {
30 if (lhs == on_overflow_t::Throw || rhs == on_overflow_t::Throw) {
31 return on_overflow_t::Throw;
32 }
else if (lhs == on_overflow_t::Saturate || rhs == on_overflow_t::Saturate) {
33 return on_overflow_t::Saturate;
34 }
else if (lhs == on_overflow_t::Assert || rhs == on_overflow_t::Assert) {
35 return on_overflow_t::Assert;
37 return on_overflow_t::Axiom;
46template<
typename T, on_overflow_t OnOverflow>
47tt_force_inline T safe_handle_overflow(T value,
bool overflow,
bool is_positive)
noexcept(OnOverflow != on_overflow_t::Throw)
49 if constexpr (OnOverflow == on_overflow_t::Throw) {
51 TTAURI_THROW(math_error(
"safe_int"));
53 }
else if constexpr (OnOverflow == on_overflow_t::Assert) {
55 }
else if constexpr (OnOverflow == on_overflow_t::Axiom) {
57 }
else if constexpr (OnOverflow == on_overflow_t::Saturate) {
58 if (tt_unlikely(overflow)) {
65template<
typename T, on_overflow_t OnOverflow,
typename U>
66tt_force_inline T safe_convert(U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
70 ttlet overflow = convert_overflow(rhs, &r);
71 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs >= 0);
74template<on_overflow_t OnOverflow,
typename T,
typename U>
75tt_force_inline make_promote_t<T,U> safe_add(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
77 make_promote_t<T,U> r;
78 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
79 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
81 ttlet overflow = add_overflow(lhs_, rhs_, &r);
82 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
85template<on_overflow_t OnOverflow,
typename T,
typename U>
86tt_force_inline make_promote_t<T,U> safe_sub(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
88 make_promote_t<T,U> r;
89 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
90 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
92 ttlet overflow = sub_overflow(lhs_, rhs_, &r);
93 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
96template<on_overflow_t OnOverflow,
typename T,
typename U>
97tt_force_inline make_promote_t<T,U> safe_mul(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
99 make_promote_t<T,U> r;
100 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
101 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
103 ttlet overflow = mul_overflow(lhs_, rhs_, &r);
104 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
107template<
typename T, on_overflow_t OnOverflow=on_overflow_t::Assert>
109 using value_type = T;
110 constexpr static on_overflow_t on_overflow = OnOverflow;
121 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
122 explicit safe_int(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
123 value(safe_convert<T,OnOverflow>(other)) {}
125 template<
typename O, std::enable_if_t<std::is_
floating_po
int_v<O>,
int> = 0>
126 explicit safe_int(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
127 value(safe_convert<T,OnOverflow>(other)) {}
129 template<
typename O, on_overflow_t OtherOnOverflow>
131 value(safe_convert<T,OnOverflow>(other.value)) {}
133 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
134 safe_int &operator=(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) {
135 value = safe_convert<T,OnOverflow>(other);
139 template<
typename O, on_overflow_t OtherOnOverflow>
141 value = safe_convert<T,OnOverflow>(other.value);
145 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
146 explicit operator O ()
const noexcept(OnOverflow != on_overflow_t::Throw) {
147 return safe_convert<O,OnOverflow>(value);
150 template<
typename O, std::enable_if_t<std::is_
floating_po
int_v<O>,
int> = 0>
151 explicit operator O ()
const noexcept {
152 return static_cast<O
>(value);
157 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO>\
158 tt_force_inline bool operator op (safe_int<T,TO> const &lhs, safe_int<U,UO> const &rhs) noexcept {\
159 return lhs.value op rhs.value;\
162 template<typename T, on_overflow_t TO, typename U>\
163 tt_force_inline bool operator op (safe_int<T,TO> const &lhs, U const &rhs) noexcept {\
164 return lhs.value op rhs;\
166 template<typename T, typename U, on_overflow_t UO>\
167 tt_force_inline bool operator op (T const &lhs, safe_int<U,UO> const &rhs) noexcept {\
168 return lhs op rhs.value;\
179#define TEMPLATE(op, func)\
180 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO>\
181 tt_force_inline safe_int<make_promote_t<T,U>,TO|UO> operator op(safe_int<T,TO> const &lhs, safe_int<U,UO> const &rhs) noexcept((TO|UO) != on_overflow_t::Throw) {\
182 return safe_int<make_promote_t<T,U>,TO|UO>{ func<TO|UO>(lhs.value, rhs.value) };\
185 template<typename T, on_overflow_t TO, typename U>\
186 tt_force_inline safe_int<make_promote_t<T,U>,TO> operator op(safe_int<T,TO> const &lhs, U const &rhs) noexcept(TO != on_overflow_t::Throw) {\
187 return safe_int<make_promote_t<T,U>,TO>{ func<TO>(lhs.value, rhs) };\
190 template<typename T, typename U, on_overflow_t UO>\
191 tt_force_inline safe_int<make_promote_t<T,U>,UO> operator op(T const &lhs, safe_int<U,UO> const &rhs) noexcept(UO != on_overflow_t::Throw) {\
192 return safe_int<make_promote_t<T,U>,UO>{ func<UO>(lhs, rhs.value) };\
Definition safe_int.hpp:108