58 constexpr bound_integer() noexcept : value(bounds.lower() <= 0 and 0 <= bounds.upper() ? 0 : bounds.lower()) {}
67 r.
value =
static_cast<value_type
>(other);
68 hi_axiom(r.holds_invariant);
72 constexpr bound_integer(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(other)>()) :
73 value(static_cast<value_type>(other))
76 if (other != bounds) {
80 hi_axiom(holds_invariant());
83 constexpr bound_integer &operator=(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(other)>())
86 if (other != bounds) {
90 value =
static_cast<value_type
>(value);
91 hi_axiom(holds_invariant());
95 template<bound_type OtherBound>
96 constexpr bound_integer(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds)) :
97 value(static_cast<value_type>(other.value))
99 if constexpr (not OtherBound.is_fully_inside(bounds)) {
100 if (other.value != bounds) {
104 hi_axiom(holds_invariant());
107 template<bound_type OtherBound>
108 constexpr bound_integer &operator=(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds))
110 if constexpr (not OtherBound.is_fully_inside(bounds)) {
111 if (other.value != bounds) {
115 value =
static_cast<value_type
>(other._value);
116 hi_axiom(holds_invariant());
120 template<numeric_
integral T>
121 explicit constexpr operator T() noexcept(values_between_bounds_fit_in_type_v<T>)
123 if constexpr (not values_between_bounds_fit_in_type_v<T>) {
129 return static_cast<T
>(value);
132 explicit constexpr operator bool() noexcept
134 if constexpr (bounds.
lower() > 0 or bounds.
upper() < 0) {
136 }
else if constexpr (bounds) {
137 return value != value_type{0};
143 [[nodiscard]]
constexpr bool holds_invariant() noexcept
145 return value == bounds;
148 [[nodiscard]]
auto operator-() const noexcept
150 using r_type = bound_integer<-bounds>;
151 return r_type::make_without_check(-
static_cast<r_type::calculation_type
>(value));
156 template<bound_type RHSBounds>
159 if constexpr (bounds.upper() < RHSBounds.lower() or bounds.lower() > RHSBounds.upper) {
161 }
else if (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
164 return value == rhs.value;
170 template<bound_type RHSBounds>
173 if constexpr (bounds.upper() < RHSBounds.lower()) {
174 return std::strong_ordering::less;
175 }
else if constexpr (bounds.lower() > RHSBounds.upper()) {
176 return std::strong_ordering::greater;
177 }
else if constexpr (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
178 return std::strong_ordering::equal;
180 return value <=> rhs.value;
184 template<bound_type RHSBounds>
193 return r_type::make_without_check(
194 static_cast<r_type::calculation_type
>(value) +
static_cast<r_type::calculation_type
>(rhs.value));
197 template<bound_type RHSBounds>
198 [[nodiscard]]
constexpr auto operator-(bound_integer<RHSBounds>
const &rhs)
noexcept
205 using r_type = bound_integer<bounds - RHSBounds>;
206 return r_type::make_without_check(
207 static_cast<r_type::calculation_type
>(value) -
static_cast<r_type::calculation_type
>(rhs.value));
210 template<bound_type RHSBounds>
211 [[nodiscard]]
constexpr auto operator*(bound_integer<RHSBounds>
const &rhs)
noexcept
218 using r_type = bound_integer<bounds * RHSBounds>;
219 return r_type::make_without_check(
220 static_cast<r_type::calculation_type
>(value) *
static_cast<r_type::calculation_type
>(rhs.value));
223 template<bound_type RHSBounds>
224 [[nodiscard]]
constexpr auto operator/(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
228 static_assert(RHSBounds,
"divide by zero");
230 if constexpr (0 == RHSBounds) {
231 if (rhs.value == 0) {
236 using r_type = bound_integer<bounds / RHSBounds>;
237 return r_type::make_without_check(
238 static_cast<r_type::calculation_type
>(value) /
static_cast<r_type::calculation_type
>(rhs.value));
241 template<bound_type RHSBounds>
242 [[nodiscard]]
constexpr auto operator%(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
244 static_assert(RHSBounds,
"divide by zero");
246 if constexpr (0 == RHSBounds) {
247 if (rhs.value == 0) {
252 using r_type = bound_integer<bounds % RHSBounds>;
253 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:29
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:44