7#include "int_overflow.hpp"
8#include "utility/module.hpp"
14namespace hi::inline
v1 {
32 if (lhs == on_overflow_t::Throw || rhs == on_overflow_t::Throw) {
33 return on_overflow_t::Throw;
34 }
else if (lhs == on_overflow_t::Saturate || rhs == on_overflow_t::Saturate) {
35 return on_overflow_t::Saturate;
36 }
else if (lhs == on_overflow_t::Assert || rhs == on_overflow_t::Assert) {
37 return on_overflow_t::Assert;
39 return on_overflow_t::Axiom;
48template<
typename T, on_overflow_t OnOverflow>
49T
safe_handle_overflow(T value,
bool overflow,
bool is_positive)
noexcept(OnOverflow != on_overflow_t::Throw)
51 if constexpr (OnOverflow == on_overflow_t::Throw) {
55 }
else if constexpr (OnOverflow == on_overflow_t::Assert) {
57 }
else if constexpr (OnOverflow == on_overflow_t::Axiom) {
59 }
else if constexpr (OnOverflow == on_overflow_t::Saturate) {
67template<
typename T, on_overflow_t OnOverflow,
typename U>
68T safe_convert(U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
72 hilet overflow = convert_overflow(rhs, &r);
73 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs >= 0);
76template<on_overflow_t OnOverflow,
typename T,
typename U>
77make_promote_t<T, U> safe_add(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
79 make_promote_t<T, U> r;
80 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
81 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
83 hilet overflow = add_overflow(lhs_, rhs_, &r);
84 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
87template<on_overflow_t OnOverflow,
typename T,
typename U>
88make_promote_t<T, U> safe_sub(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
90 make_promote_t<T, U> r;
91 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
92 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
94 hilet overflow = sub_overflow(lhs_, rhs_, &r);
95 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
98template<on_overflow_t OnOverflow,
typename T,
typename U>
99make_promote_t<T, U> safe_mul(T
const &lhs, U
const &rhs)
noexcept(OnOverflow != on_overflow_t::Throw)
101 make_promote_t<T, U> r;
102 hilet lhs_ =
static_cast<make_promote_t<T, U>
>(lhs);
103 hilet rhs_ =
static_cast<make_promote_t<T, U>
>(rhs);
106 return safe_handle_overflow<T, OnOverflow>(r, overflow, rhs_ >= 0);
109template<
typename T, on_overflow_t OnOverflow = on_overflow_t::Assert>
111 using value_type = T;
123 explicit safe_int(std::integral
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
124 value(safe_convert<T, OnOverflow>(other))
128 explicit safe_int(std::floating_point
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw) :
129 value(safe_convert<T, OnOverflow>(other))
133 template<
typename O, on_overflow_t OtherOnOverflow>
135 value(safe_convert<T, OnOverflow>(other.value))
139 safe_int &operator=(std::integral
auto const &other)
noexcept(OnOverflow != on_overflow_t::Throw)
141 value = safe_convert<T, OnOverflow>(other);
145 template<
typename O, on_overflow_t OtherOnOverflow>
148 value = safe_convert<T, OnOverflow>(other.value);
152 template<std::
integral O>
153 explicit operator O()
const noexcept(OnOverflow != on_overflow_t::Throw)
155 return safe_convert<O, OnOverflow>(value);
158 template<std::
floating_po
int O>
159 explicit operator O()
const noexcept
161 return static_cast<O
>(value);
165#define TEMPLATE(op) \
166 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO> \
167 bool operator op(safe_int<T, TO> const &lhs, safe_int<U, UO> const &rhs) noexcept \
169 return lhs.value op rhs.value; \
172 template<typename T, on_overflow_t TO, typename U> \
173 bool operator op(safe_int<T, TO> const &lhs, U const &rhs) noexcept \
175 return lhs.value op rhs; \
177 template<typename T, typename U, on_overflow_t UO> \
178 bool operator op(T const &lhs, safe_int<U, UO> const &rhs) noexcept \
180 return lhs op rhs.value; \
191#define TEMPLATE(op, func) \
192 template<typename T, on_overflow_t TO, typename U, on_overflow_t UO> \
193 safe_int<make_promote_t<T, U>, TO | UO> operator op(safe_int<T, TO> const &lhs, safe_int<U, UO> const &rhs) noexcept( \
194 (TO | UO) != on_overflow_t::Throw) \
196 return safe_int<make_promote_t<T, U>, TO | UO>{func<TO | UO>(lhs.value, rhs.value)}; \
199 template<typename T, on_overflow_t TO, typename U> \
200 safe_int<make_promote_t<T, U>, TO> operator op(safe_int<T, TO> const &lhs, U const &rhs) noexcept( \
201 TO != on_overflow_t::Throw) \
203 return safe_int<make_promote_t<T, U>, TO>{func<TO>(lhs.value, rhs)}; \
206 template<typename T, typename U, on_overflow_t UO> \
207 safe_int<make_promote_t<T, U>, UO> operator op(T const &lhs, safe_int<U, UO> const &rhs) noexcept( \
208 UO != on_overflow_t::Throw) \
210 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:184
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
T safe_handle_overflow(T value, bool overflow, bool is_positive) noexcept(OnOverflow !=on_overflow_t::Throw)
Definition safe_int.hpp:49
constexpr 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:16
@ 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 cache.hpp:11
Definition safe_int.hpp:110