64 constexpr bound_integer() noexcept : value(bounds.lower() <= 0 and 0 <= bounds.upper() ? 0 : bounds.lower()) {}
70 [[nodiscard]] constexpr static
bound_integer make_without_check(numeric_limited auto other) noexcept
73 r.
value =
static_cast<value_type
>(other);
74 hi_axiom(r.holds_invariant);
78 constexpr bound_integer(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(other)>()) :
79 value(static_cast<value_type>(other))
82 if (other != bounds) {
86 hi_axiom(holds_invariant());
89 constexpr bound_integer &operator=(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(
other)>())
92 if (other != bounds) {
96 value =
static_cast<value_type
>(value);
97 hi_axiom(holds_invariant());
101 template<bound_type OtherBound>
102 constexpr bound_integer(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds)) :
103 value(static_cast<value_type>(
other.value))
105 if constexpr (not OtherBound.is_fully_inside(bounds)) {
106 if (
other.value != bounds) {
110 hi_axiom(holds_invariant());
113 template<bound_type OtherBound>
114 constexpr bound_integer &operator=(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds))
116 if constexpr (not OtherBound.is_fully_inside(bounds)) {
117 if (
other.value != bounds) {
121 value =
static_cast<value_type
>(
other._value);
122 hi_axiom(holds_invariant());
138 explicit constexpr operator bool() noexcept
140 if constexpr (bounds.
lower() > 0 or bounds.
upper() < 0) {
142 }
else if constexpr (bounds) {
143 return value != value_type{0};
149 [[nodiscard]]
constexpr bool holds_invariant() noexcept
151 return value == bounds;
154 [[nodiscard]]
auto operator-() const noexcept
156 using r_type = bound_integer<-bounds>;
157 return r_type::make_without_check(-
static_cast<r_type::calculation_type
>(value));
162 template<bound_type RHSBounds>
165 if constexpr (bounds.upper() < RHSBounds.lower() or bounds.lower() > RHSBounds.upper) {
167 }
else if (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
170 return value == rhs.value;
176 template<bound_type RHSBounds>
179 if constexpr (bounds.upper() < RHSBounds.lower()) {
180 return std::strong_ordering::less;
181 }
else if constexpr (bounds.lower() > RHSBounds.upper()) {
182 return std::strong_ordering::greater;
183 }
else if constexpr (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
184 return std::strong_ordering::equal;
186 return value <=> rhs.value;
190 template<bound_type RHSBounds>
199 return r_type::make_without_check(
200 static_cast<r_type::calculation_type
>(value) +
static_cast<r_type::calculation_type
>(rhs.value));
203 template<bound_type RHSBounds>
204 [[nodiscard]]
constexpr auto operator-(bound_integer<RHSBounds>
const &rhs)
noexcept
211 using r_type = bound_integer<bounds - RHSBounds>;
212 return r_type::make_without_check(
213 static_cast<r_type::calculation_type
>(value) -
static_cast<r_type::calculation_type
>(rhs.value));
216 template<bound_type RHSBounds>
217 [[nodiscard]]
constexpr auto operator*(bound_integer<RHSBounds>
const &rhs)
noexcept
224 using r_type = bound_integer<bounds * RHSBounds>;
225 return r_type::make_without_check(
226 static_cast<r_type::calculation_type
>(value) *
static_cast<r_type::calculation_type
>(rhs.value));
229 template<bound_type RHSBounds>
230 [[nodiscard]]
constexpr auto operator/(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
234 static_assert(RHSBounds,
"divide by zero");
236 if constexpr (0 == RHSBounds) {
237 if (rhs.value == 0) {
242 using r_type = bound_integer<bounds / RHSBounds>;
243 return r_type::make_without_check(
244 static_cast<r_type::calculation_type
>(value) /
static_cast<r_type::calculation_type
>(rhs.value));
247 template<bound_type RHSBounds>
248 [[nodiscard]]
constexpr auto operator%(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
250 static_assert(RHSBounds,
"divide by zero");
252 if constexpr (0 == RHSBounds) {
253 if (rhs.value == 0) {
258 using r_type = bound_integer<bounds % RHSBounds>;
259 return r_type::make_without_check(value % rhs.value);
std::conditional_t< bounds.type_contains_range< signed char >(), signed char, std::conditional_t< bounds.type_contains_range< unsigned char >(), unsigned char, std::conditional_t< bounds.type_contains_range< signed short >(), signed short, std::conditional_t< bounds.type_contains_range< unsigned short >(), unsigned short, std::conditional_t< bounds.type_contains_range< signed int >(), signed int, std::conditional_t< bounds.type_contains_range< unsigned int >(), unsigned int, std::conditional_t< bounds.type_contains_range< signed long >(), signed long, std::conditional_t< bounds.type_contains_range< unsigned long >(), unsigned long, std::conditional_t< bounds.type_contains_range< signed long long >(), signed long long, std::conditional_t< bounds.type_contains_range< unsigned long long >(), unsigned long long, longreg_t > > > > > > > > > > value_type
The type that can hold the value of the bound integer.
Definition bound_integer.hpp:35
std::conditional_t< bounds.type_contains_range< signed char >(), signed char, std::conditional_t< bounds.type_contains_range< signed short >(), signed short, std::conditional_t< bounds.type_contains_range< signed int >(), signed int, std::conditional_t< bounds.type_contains_range< signed long >(), signed long, std::conditional_t< bounds.type_contains_range< signed long long >(), signed long long, longreg_t > > > > > calculation_type
The type that is used as a temporary during calculation.
Definition bound_integer.hpp:50