7 #if !defined(CNL_IMPL_DUPLEX_INTEGER_DEFINITION_H)
8 #define CNL_IMPL_DUPLEX_INTEGER_DEFINITION_H
10 #include "../num_traits/width.h"
11 #include "../numbers/set_signedness.h"
12 #include "../power_value.h"
13 #include "../unreachable.h"
14 #include "declaration.h"
25 template<
typename Integer>
26 [[nodiscard]] constexpr
auto is_flushed(Integer
const& value)
28 return value == 0 || value ==
static_cast<Integer
>(~Integer{});
31 template<
typename Result,
typename Upper,
typename Lower>
32 [[nodiscard]] constexpr
auto upper_value(Upper
const& upper) -> Result
34 return (digits_v<Result> <= digits_v<Lower>)
36 ? unreachable<Result>(
"overflow in narrowing conversion")
38 : Result(sensible_left_shift<Result>(upper, digits_v<Lower>));
44 template<
typename Upper,
typename Lower>
45 class duplex_integer {
46 static_assert(!numbers::signedness_v<Lower>,
"Lower component must be unsigned.");
48 using upper_type = Upper;
49 using lower_type = Lower;
51 static constexpr
int lower_width = width<lower_type>;
54 duplex_integer() =
default;
56 constexpr duplex_integer(upper_type
const& u, lower_type
const& l);
58 template<
integer Number>
59 constexpr duplex_integer(Number
const& n);
61 template<std::
floating_po
int Number>
62 constexpr duplex_integer(Number
const& n);
64 [[nodiscard]] constexpr
auto upper() const -> upper_type const&
69 constexpr
auto upper() -> upper_type&
74 [[nodiscard]] constexpr
auto lower() const -> lower_type const&
79 constexpr
auto lower() -> lower_type&
84 [[nodiscard]]
explicit constexpr
operator bool()
const
86 return _lower || _upper;
89 template<
integer Integer>
90 [[nodiscard]]
explicit constexpr
operator Integer()
const
92 return upper_value<Integer, Upper, Lower>(_upper) |
static_cast<Integer
>(_lower);
95 template<std::
floating_po
int Number>
96 [[nodiscard]]
explicit constexpr
operator Number()
const
98 return static_cast<Number
>(_upper) * power_value<Number, lower_width, 2>()
99 +
static_cast<Number
>(_lower);
110 #endif // CNL_IMPL_DUPLEX_INTEGER_DEFINITION_H