61 constexpr bound_integer() noexcept : value(bounds.lower() <= 0 and 0 <= bounds.upper() ? 0 : bounds.lower()) {}
70 r.
value =
static_cast<value_type
>(other);
71 hi_axiom(r.holds_invariant);
75 constexpr bound_integer(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(other)>()) :
76 value(static_cast<value_type>(other))
79 if (other != bounds) {
83 hi_axiom(holds_invariant());
86 constexpr bound_integer &operator=(numeric_limited
auto other)
noexcept(bounds.
range_contains_type<
decltype(other)>())
89 if (other != bounds) {
93 value =
static_cast<value_type
>(value);
94 hi_axiom(holds_invariant());
98 template<bound_type OtherBound>
99 constexpr bound_integer(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds)) :
100 value(static_cast<value_type>(other.value))
102 if constexpr (not OtherBound.is_fully_inside(bounds)) {
103 if (other.value != bounds) {
107 hi_axiom(holds_invariant());
110 template<bound_type OtherBound>
111 constexpr bound_integer &operator=(bound_integer<OtherBound> other)
noexcept(OtherBound.is_fully_inside(bounds))
113 if constexpr (not OtherBound.is_fully_inside(bounds)) {
114 if (other.value != bounds) {
118 value =
static_cast<value_type
>(other._value);
119 hi_axiom(holds_invariant());
123 template<numeric_
integral T>
124 explicit constexpr operator T() noexcept(values_between_bounds_fit_in_type_v<T>)
126 if constexpr (not values_between_bounds_fit_in_type_v<T>) {
132 return static_cast<T
>(value);
135 explicit constexpr operator bool() noexcept
137 if constexpr (bounds.
lower() > 0 or bounds.
upper() < 0) {
139 }
else if constexpr (bounds) {
140 return value != value_type{0};
146 [[nodiscard]]
constexpr bool holds_invariant() noexcept
148 return value == bounds;
151 [[nodiscard]]
auto operator-() const noexcept
153 using r_type = bound_integer<-bounds>;
154 return r_type::make_without_check(-
static_cast<r_type::calculation_type
>(value));
159 template<bound_type RHSBounds>
162 if constexpr (bounds.upper() < RHSBounds.lower() or bounds.lower() > RHSBounds.upper) {
164 }
else if (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
167 return value == rhs.value;
173 template<bound_type RHSBounds>
176 if constexpr (bounds.upper() < RHSBounds.lower()) {
177 return std::strong_ordering::less;
178 }
else if constexpr (bounds.lower() > RHSBounds.upper()) {
179 return std::strong_ordering::greater;
180 }
else if constexpr (bounds.is_value() and RHSBounds.is_value() and bounds.lower() == RHSBounds.lower()) {
181 return std::strong_ordering::equal;
183 return value <=> rhs.value;
187 template<bound_type RHSBounds>
196 return r_type::make_without_check(
197 static_cast<r_type::calculation_type
>(value) +
static_cast<r_type::calculation_type
>(rhs.value));
200 template<bound_type RHSBounds>
201 [[nodiscard]]
constexpr auto operator-(bound_integer<RHSBounds>
const &rhs)
noexcept
208 using r_type = bound_integer<bounds - RHSBounds>;
209 return r_type::make_without_check(
210 static_cast<r_type::calculation_type
>(value) -
static_cast<r_type::calculation_type
>(rhs.value));
213 template<bound_type RHSBounds>
214 [[nodiscard]]
constexpr auto operator*(bound_integer<RHSBounds>
const &rhs)
noexcept
221 using r_type = bound_integer<bounds * RHSBounds>;
222 return r_type::make_without_check(
223 static_cast<r_type::calculation_type
>(value) *
static_cast<r_type::calculation_type
>(rhs.value));
226 template<bound_type RHSBounds>
227 [[nodiscard]]
constexpr auto operator/(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
231 static_assert(RHSBounds,
"divide by zero");
233 if constexpr (0 == RHSBounds) {
234 if (rhs.value == 0) {
239 using r_type = bound_integer<bounds / RHSBounds>;
240 return r_type::make_without_check(
241 static_cast<r_type::calculation_type
>(value) /
static_cast<r_type::calculation_type
>(rhs.value));
244 template<bound_type RHSBounds>
245 [[nodiscard]]
constexpr auto operator%(bound_integer<RHSBounds>
const &rhs)
noexcept(0 != RHSBounds)
247 static_assert(RHSBounds,
"divide by zero");
249 if constexpr (0 == RHSBounds) {
250 if (rhs.value == 0) {
255 using r_type = bound_integer<bounds % RHSBounds>;
256 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:32
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:47