7 #if !defined(CNL_IMPL_ELASTIC_INTEGER_GENERIC_H)
8 #define CNL_IMPL_ELASTIC_INTEGER_GENERIC_H
10 #include "../custom_operator/definition.h"
11 #include "definition.h"
22 template<
class T1,
class T2>
23 struct common_signedness {
24 static constexpr
bool _are_signed =
25 numbers::signedness_v<T1> | numbers::signedness_v<T2>;
28 numbers::set_signedness_t<T1, _are_signed>,
29 numbers::set_signedness_t<T2, _are_signed>>::type;
32 template<
class T1,
class T2>
33 using common_signedness_t =
typename common_signedness<T1, T2>::type;
38 template<
typename T1,
typename T2>
39 struct common_elastic_type;
41 template<
int Digits1,
class Narrowest1,
int Digits2,
class Narrowest2>
42 struct common_elastic_type<
45 std::max(Digits1, Digits2), common_signedness_t<Narrowest1, Narrowest2>>;
48 template<
int Digits1,
class Narrowest1,
class Rhs>
50 : common_elastic_type<
51 elastic_integer<Digits1, Narrowest1>,
52 elastic_integer<std::numeric_limits<Rhs>::digits, Rhs>> {
55 template<
class Lhs,
int Digits2,
class Narrowest2>
57 : common_elastic_type<
58 elastic_integer<std::numeric_limits<Lhs>::digits, Lhs>,
59 elastic_integer<Digits2, Narrowest2>> {
62 template<
int FromDigits,
class FromNarrowest,
int OtherDigits,
class OtherNarrowest>
64 [[nodiscard]] constexpr
auto cast_to_common_type(
65 elastic_integer<FromDigits, FromNarrowest>
const& from,
66 elastic_integer<OtherDigits, OtherNarrowest>
const&)
68 return static_cast<typename common_elastic_type<
69 elastic_integer<FromDigits, FromNarrowest>,
70 elastic_integer<OtherDigits, OtherNarrowest>
>::type>(from);
74 template<_impl::comparison_op Operator,
int LhsDigits,
class LhsNarrowest,
int RhsDigits,
class RhsNarrowest>
75 requires(!std::is_same_v<elastic_tag<LhsDigits, LhsNarrowest>, elastic_tag<RhsDigits, RhsNarrowest>>) struct custom_operator<
79 [[nodiscard]] constexpr
auto operator()(
80 elastic_integer<LhsDigits, LhsNarrowest>
const& lhs,
81 elastic_integer<RhsDigits, RhsNarrowest>
const& rhs)
const
83 return Operator()(cast_to_common_type(lhs, rhs), cast_to_common_type(rhs, lhs));
89 template<_impl::shift_op Operator,
integer LhsRep,
int LhsDigits,
integer LhsNarrowest,
typename Rhs>
90 requires(!_impl::is_constant<Rhs>::value)
struct custom_operator<
92 op_value<_impl::wrapper<LhsRep, elastic_tag<LhsDigits, LhsNarrowest>>>,
94 using lhs_type = _impl::wrapper<LhsRep, elastic_tag<LhsDigits, LhsNarrowest>>;
96 [[nodiscard]] constexpr
auto operator()(lhs_type
const& lhs, Rhs
const& rhs)
const
98 return _impl::from_rep<lhs_type>(Operator{}(_impl::to_rep(lhs), rhs));
102 template<
int LhsDigits,
class LhsNarrowest, CNL_IMPL_CONSTANT_VALUE_TYPE RhsValue>
103 struct custom_operator<
104 _impl::shift_left_op,
105 op_value<elastic_integer<LhsDigits, LhsNarrowest>>,
106 op_value<constant<RhsValue>>> {
107 [[nodiscard]] constexpr
auto operator()(
108 elastic_integer<LhsDigits, LhsNarrowest>
const& lhs, constant<RhsValue>)
const
110 return _impl::from_rep<
elastic_integer<LhsDigits +
int{RhsValue}, LhsNarrowest>>(
118 template<
integer LhsRep,
int LhsDigits,
integer LhsNarrowest, CNL_IMPL_CONSTANT_VALUE_TYPE RhsValue>
119 struct custom_operator<
120 _impl::shift_right_op,
121 op_value<_impl::wrapper<LhsRep, elastic_tag<LhsDigits, LhsNarrowest>>>,
122 op_value<constant<RhsValue>>> {
123 [[nodiscard]] constexpr
auto operator()(
124 elastic_integer<LhsDigits, LhsNarrowest>
const& lhs, constant<RhsValue>)
const
126 return _impl::from_rep<
elastic_integer<LhsDigits -
int{RhsValue}, LhsNarrowest>>(
127 _impl::to_rep(
static_cast<elastic_integer<LhsDigits, LhsNarrowest>
>(lhs))
134 struct tag_narrowest;
136 template<
int Digits,
typename Narrowest>
137 struct tag_narrowest<elastic_tag<Digits, Narrowest>> : std::type_identity<Narrowest> {
141 using tag_narrowest_t =
typename tag_narrowest<T>::type;
145 template<_impl::unary_arithmetic_op Operator,
integer RhsRep,
int RhsDigits,
integer RhsNarrowest>
146 requires(!std::is_same_v<_impl::bitwise_not_op, Operator>)
struct custom_operator<Operator, op_value<_impl::wrapper<RhsRep, elastic_tag<RhsDigits, RhsNarrowest>>>> {
147 using rhs_type = _impl::wrapper<RhsRep, elastic_tag<RhsDigits, RhsNarrowest>>;
148 [[nodiscard]] constexpr
auto operator()(rhs_type
const& rhs)
const
150 constexpr
auto result_digits = digits_v<rhs_type>;
151 using rhs_narrowest = _impl::tag_narrowest_t<_impl::tag_of_t<rhs_type>>;
152 using result_narrowest = numbers::set_signedness_t<rhs_narrowest, true>;
153 using result_type = elastic_integer<result_digits, result_narrowest>;
154 return _impl::from_rep<result_type>(Operator{}(_impl::to_rep(
static_cast<result_type
>(rhs))));
159 template<
integer RhsRep,
int RhsDigits,
integer RhsNarrowest>
160 struct custom_operator<
161 _impl::bitwise_not_op, op_value<_impl::wrapper<RhsRep, elastic_tag<RhsDigits, RhsNarrowest>>>> {
162 [[nodiscard]] constexpr
auto operator()(
163 _impl::wrapper<RhsRep, elastic_tag<RhsDigits, RhsNarrowest>>
const& rhs)
165 using elastic_integer = _impl::wrapper<RhsRep, elastic_tag<RhsDigits, RhsNarrowest>>;
166 using rep = _impl::rep_of_t<elastic_integer>;
167 return _impl::from_rep<elastic_integer>(
static_cast<rep
>(
174 #endif // CNL_IMPL_ELASTIC_INTEGER_GENERIC_H