7#include "int_overflow.hpp"
8#include "type_traits.hpp"
9#include "exception.hpp"
10#include <system_error>
16enum class on_overflow_t {
30constexpr on_overflow_t operator|(on_overflow_t lhs, on_overflow_t rhs)
noexcept {
31 if (lhs == on_overflow_t::Throw || rhs == on_overflow_t::Throw) {
32 return on_overflow_t::Throw;
33 }
else if (lhs == on_overflow_t::Saturate || rhs == on_overflow_t::Saturate) {
34 return on_overflow_t::Saturate;
35 }
else if (lhs == on_overflow_t::Assert || rhs == on_overflow_t::Assert) {
36 return on_overflow_t::Assert;
38 return on_overflow_t::Axiom;
47template<
typename T, on_overflow_t OnOverflow>
48T safe_handle_overflow(T value,
bool overflow,
bool is_positive)
noexcept(OnOverflow != on_overflow_t::Throw)
50 if constexpr (OnOverflow == on_overflow_t::Throw) {
54 }
else if constexpr (OnOverflow == on_overflow_t::Assert) {
56 }
else if constexpr (OnOverflow == on_overflow_t::Axiom) {
58 }
else if constexpr (OnOverflow == on_overflow_t::Saturate) {
66template<
typename T, on_overflow_t OnOverflow,
typename U>
67T safe_convert(U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
71 ttlet overflow = convert_overflow(rhs, &r);
72 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs >= 0);
75template<on_overflow_t OnOverflow,
typename T,
typename U>
76make_promote_t<T,U> safe_add(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
78 make_promote_t<T,U> r;
79 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
80 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
82 ttlet overflow = add_overflow(lhs_, rhs_, &r);
83 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
86template<on_overflow_t OnOverflow,
typename T,
typename U>
87make_promote_t<T,U> safe_sub(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
89 make_promote_t<T,U> r;
90 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
91 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
93 ttlet overflow = sub_overflow(lhs_, rhs_, &r);
94 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
97template<on_overflow_t OnOverflow,
typename T,
typename U>
98make_promote_t<T,U> safe_mul(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
100 make_promote_t<T,U> r;
101 ttlet lhs_ =
static_cast<make_promote_t<T,U>
>(lhs);
102 ttlet rhs_ =
static_cast<make_promote_t<T,U>
>(rhs);
104 ttlet overflow = mul_overflow(lhs_, rhs_, &r);
105 return safe_handle_overflow<T,OnOverflow>(r, overflow, rhs_ >= 0);
108template<
typename T, on_overflow_t OnOverflow=on_overflow_t::Assert>
110 using value_type = T;
111 constexpr static on_overflow_t on_overflow = OnOverflow;
122 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
123 explicit safe_int(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
124 value(safe_convert<T,OnOverflow>(other)) {}
126 template<
typename O, std::enable_if_t<std::is_
floating_po
int_v<O>,
int> = 0>
127 explicit safe_int(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
128 value(safe_convert<T,OnOverflow>(other)) {}
130 template<
typename O, on_overflow_t OtherOnOverflow>
132 value(safe_convert<T,OnOverflow>(other.value)) {}
134 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
135 safe_int &operator=(O
const &other)
noexcept(OnOverflow != on_overflow_t::Throw) {
136 value = safe_convert<T,OnOverflow>(other);
140 template<
typename O, on_overflow_t OtherOnOverflow>
142 value = safe_convert<T,OnOverflow>(other.value);
146 template<
typename O, std::enable_if_t<std::is_
integral_v<O>,
int> = 0>
147 explicit operator O ()
const noexcept(OnOverflow != on_overflow_t::Throw) {
148 return safe_convert<O,OnOverflow>(value);
151 template<
typename O, std::enable_if_t<std::is_
floating_po
int_v<O>,
int> = 0>
152 explicit operator O ()
const noexcept {
153 return static_cast<O
>(value);
158 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO>\
159 bool operator op (safe_int<T,TO> const &lhs, safe_int<U,UO> const &rhs) noexcept {\
160 return lhs.value op rhs.value;\
163 template<typename T, on_overflow_t TO, typename U>\
164 bool operator op (safe_int<T,TO> const &lhs, U const &rhs) noexcept {\
165 return lhs.value op rhs;\
167 template<typename T, typename U, on_overflow_t UO>\
168 bool operator op (T const &lhs, safe_int<U,UO> const &rhs) noexcept {\
169 return lhs op rhs.value;\
180#define TEMPLATE(op, func)\
181 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO>\
182 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) {\
183 return safe_int<make_promote_t<T,U>,TO|UO>{ func<TO|UO>(lhs.value, rhs.value) };\
186 template<typename T, on_overflow_t TO, typename U>\
187 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) {\
188 return safe_int<make_promote_t<T,U>,TO>{ func<TO>(lhs.value, rhs) };\
191 template<typename T, typename U, on_overflow_t UO>\
192 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) {\
193 return safe_int<make_promote_t<T,U>,UO>{ func<UO>(lhs, rhs.value) };\
Definition safe_int.hpp:109