7#include "int_overflow.hpp"
9#include "exception.hpp"
10#include <system_error>
15namespace hi::inline
v1 {
33 if (lhs == on_overflow_t::Throw || rhs == on_overflow_t::Throw) {
34 return on_overflow_t::Throw;
35 }
else if (lhs == on_overflow_t::Saturate || rhs == on_overflow_t::Saturate) {
36 return on_overflow_t::Saturate;
37 }
else if (lhs == on_overflow_t::Assert || rhs == on_overflow_t::Assert) {
38 return on_overflow_t::Assert;
40 return on_overflow_t::Axiom;
49template<
typename T, on_overflow_t OnOverflow>
50T
safe_handle_overflow(T value,
bool overflow,
bool is_positive)
noexcept(OnOverflow != on_overflow_t::Throw)
52 if constexpr (OnOverflow == on_overflow_t::Throw) {
56 }
else if constexpr (OnOverflow == on_overflow_t::Assert) {
58 }
else if constexpr (OnOverflow == on_overflow_t::Axiom) {
60 }
else if constexpr (OnOverflow == on_overflow_t::Saturate) {
68template<
typename T, on_overflow_t OnOverflow,
typename U>
69T safe_convert(U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
73 hilet overflow = convert_overflow(rhs, &r);
74 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs >= 0);
77template<on_overflow_t OnOverflow,
typename T,
typename U>
78make_promote_t<T, U> safe_add(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
80 make_promote_t<T, U> r;
81 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
82 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
84 hilet overflow = add_overflow(lhs_, rhs_, &r);
85 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
88template<on_overflow_t OnOverflow,
typename T,
typename U>
89make_promote_t<T, U> safe_sub(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
91 make_promote_t<T, U> r;
92 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
93 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
95 hilet overflow = sub_overflow(lhs_, rhs_, &r);
96 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
99template<on_overflow_t OnOverflow,
typename T,
typename U>
100make_promote_t<T, U> safe_mul(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
102 make_promote_t<T, U> r;
103 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
104 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
107 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
110template<
typename T, on_overflow_t OnOverflow = on_overflow_t::Assert>
112 using value_type = T;
124 explicit safe_int(std::integral
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
125 value(safe_convert<T, OnOverflow>(other))
129 explicit safe_int(std::floating_point
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
130 value(safe_convert<T, OnOverflow>(other))
134 template<
typename O, on_overflow_t OtherOnOverflow>
136 value(safe_convert<T, OnOverflow>(other.value))
140 safe_int &operator=(std::integral
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw)
142 value = safe_convert<T, OnOverflow>(other);
146 template<
typename O, on_overflow_t OtherOnOverflow>
149 value = safe_convert<T, OnOverflow>(other.value);
153 template<std::
integral O>
154 explicit operator O()
const noexcept(OnOverflow != on_overflow_t::Throw)
156 return safe_convert<O, OnOverflow>(value);
159 template<std::
floating_po
int O>
160 explicit operator O()
const noexcept
162 return static_cast<O
>(value);
166#define TEMPLATE(op) \
167 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO> \
168 bool operator op(safe_int<T, TO> const &lhs, safe_int<U, UO> const &rhs) noexcept \
170 return lhs.value op rhs.value; \
173 template<typename T, on_overflow_t TO, typename U> \
174 bool operator op(safe_int<T, TO> const &lhs, U const &rhs) noexcept \
176 return lhs.value op rhs; \
178 template<typename T, typename U, on_overflow_t UO> \
179 bool operator op(T const &lhs, safe_int<U, UO> const &rhs) noexcept \
181 return lhs op rhs.value; \
192#define TEMPLATE(op, func) \
193 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO> \
194 safe_int<make_promote_t<T, U>, TO | UO> operator op(safe_int<T, TO> const &lhs, safe_int<U, UO> const &rhs) noexcept( \
195 (TO | UO) != on_overflow_t::Throw) \
197 return safe_int<make_promote_t<T, U>, TO | UO>{func<TO | UO>(lhs.value, rhs.value)}; \
200 template<typename T, on_overflow_t TO, typename U> \
201 safe_int<make_promote_t<T, U>, TO> operator op(safe_int<T, TO> const &lhs, U const &rhs) noexcept( \
202 TO != on_overflow_t::Throw) \
204 return safe_int<make_promote_t<T, U>, TO>{func<TO>(lhs.value, rhs)}; \
207 template<typename T, typename U, on_overflow_t UO> \
208 safe_int<make_promote_t<T, U>, UO> operator op(T const &lhs, safe_int<U, UO> const &rhs) noexcept( \
209 UO != on_overflow_t::Throw) \
211 return safe_int<make_promote_t<T, U>, UO>{func<UO>(lhs, rhs.value)}; \
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:87
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
T safe_handle_overflow(T value, bool overflow, bool is_positive) noexcept(OnOverflow !=on_overflow_t::Throw)
Definition safe_int.hpp:50
bool mul_overflow(T lhs, T rhs, T *r) noexcept
Multiply with overflow detection.
Definition int_overflow.hpp:95
on_overflow_t
Definition safe_int.hpp:17
@ Axiom
On overflow assert and teminate in debug, assume in release.
@ Throw
On overflow throw an exception.
@ Assert
On overflow assert and terminate.
@ Saturate
On overflow saturate the result in the appropiate direction.
geometry/margins.hpp
Definition assert.hpp:18
Definition safe_int.hpp:111