11module ;
22
3- #include < cmath>
43#include < compare>
54#include < concepts>
6- #include < cstdint>
75#include < expected>
8- #include < limits>
9- #include < optional>
106#include < type_traits>
117#include < utility>
128
@@ -17,9 +13,11 @@ import mcpplibs.primitives.operations.dispatcher;
1713import mcpplibs.primitives.operations.impl;
1814import mcpplibs.primitives.primitive.impl;
1915import mcpplibs.primitives.primitive.traits;
16+ import mcpplibs.primitives.conversion.traits;
17+ import mcpplibs.primitives.conversion.underlying;
2018import mcpplibs.primitives.policy.handler;
2119import mcpplibs.primitives.policy.impl;
22- import mcpplibs.primitives.underlying;
20+ import mcpplibs.primitives.underlying.traits ;
2321
2422
2523namespace mcpplibs ::primitives::operations::details {
@@ -62,128 +60,14 @@ constexpr auto decode_three_way_code(CommonRep const &code) -> Ordering {
6260 return Ordering::equivalent;
6361}
6462
65- enum class assign_risk : unsigned char {
66- overflow,
67- underflow,
68- domain_error,
69- precision_loss,
70- };
71-
72- template <typename DestRep, typename SrcRep>
73- concept statically_castable = requires (SrcRep value) {
74- static_cast <std::remove_cvref_t <DestRep>>(value);
75- };
76-
77- template <std_integer DestRep, std_integer SrcRep>
78- constexpr auto numeric_risk (SrcRep value) -> std::optional<assign_risk> {
79- using dest_type = std::remove_cvref_t <DestRep>;
80- using src_type = std::remove_cvref_t <SrcRep>;
81-
82- if constexpr (std::is_signed_v<src_type>) {
83- auto const signed_value = static_cast <std::intmax_t >(value);
84- if constexpr (std::is_signed_v<dest_type>) {
85- if (signed_value <
86- static_cast <std::intmax_t >(std::numeric_limits<dest_type>::min ())) {
87- return assign_risk::underflow;
88- }
89- if (signed_value >
90- static_cast <std::intmax_t >(std::numeric_limits<dest_type>::max ())) {
91- return assign_risk::overflow;
92- }
93- } else {
94- if (signed_value < 0 ) {
95- return assign_risk::underflow;
96- }
97- if (static_cast <std::uintmax_t >(signed_value) >
98- static_cast <std::uintmax_t >(std::numeric_limits<dest_type>::max ())) {
99- return assign_risk::overflow;
100- }
101- }
102- } else {
103- auto const unsigned_value = static_cast <std::uintmax_t >(value);
104- if (unsigned_value >
105- static_cast <std::uintmax_t >(std::numeric_limits<dest_type>::max ())) {
106- return assign_risk::overflow;
107- }
108- }
109-
110- return std::nullopt ;
111- }
112-
113- template <std_integer DestRep, std_floating SrcRep>
114- constexpr auto numeric_risk (SrcRep value) -> std::optional<assign_risk> {
115- using dest_type = std::remove_cvref_t <DestRep>;
116- using src_type = std::remove_cvref_t <SrcRep>;
117-
118- if (std::isnan (value)) {
119- return assign_risk::domain_error;
120- }
121- if (std::isinf (value)) {
122- return value < static_cast <src_type>(0 ) ? assign_risk::underflow
123- : assign_risk::overflow;
124- }
125-
126- auto const normalized = static_cast <long double >(value);
127- auto const min_value =
128- static_cast <long double >(std::numeric_limits<dest_type>::lowest ());
129- auto const max_value =
130- static_cast <long double >(std::numeric_limits<dest_type>::max ());
131-
132- if (normalized < min_value) {
133- return assign_risk::underflow;
134- }
135- if (normalized > max_value) {
136- return assign_risk::overflow;
137- }
138- return std::nullopt ;
139- }
140-
141- template <typename DestRep, typename SrcRep>
142- constexpr auto numeric_risk (SrcRep value) -> std::optional<assign_risk> {
143- using dest_type = std::remove_cvref_t <DestRep>;
144- using src_type = std::remove_cvref_t <SrcRep>;
145-
146- if constexpr (std_integer<dest_type> && std_integer<src_type>) {
147- return numeric_risk<dest_type, src_type>(value);
148- } else if constexpr (std_integer<dest_type> && std_floating<src_type>) {
149- return numeric_risk<dest_type, src_type>(value);
150- } else {
151- return std::nullopt ;
152- }
153- }
154-
155- template <typename DestRep, typename SrcRep>
156- requires statically_castable<DestRep, SrcRep>
157- constexpr auto saturating_rep_cast (SrcRep value) noexcept
158- -> std::remove_cvref_t<DestRep> {
159- using dest_type = std::remove_cvref_t <DestRep>;
160- using src_type = std::remove_cvref_t <SrcRep>;
161-
162- if constexpr (std_integer<dest_type> && std_numeric<src_type>) {
163- if (auto const kind = numeric_risk<dest_type>(value); kind.has_value ()) {
164- if (*kind == assign_risk::overflow) {
165- return std::numeric_limits<dest_type>::max ();
166- }
167- if (*kind == assign_risk::underflow) {
168- return std::numeric_limits<dest_type>::lowest ();
169- }
170- if (*kind == assign_risk::domain_error) {
171- return dest_type{};
172- }
173- }
174- }
175-
176- return static_cast <dest_type>(value);
177- }
178-
179- constexpr auto to_policy_error_kind (assign_risk kind)
63+ constexpr auto to_policy_error_kind (const conversion::risk::kind kind)
18064 -> policy::error::kind {
18165 switch (kind) {
182- case assign_risk ::overflow:
66+ case conversion::risk::kind ::overflow:
18367 return policy::error::kind::overflow;
184- case assign_risk ::underflow:
68+ case conversion::risk::kind ::underflow:
18569 return policy::error::kind::underflow;
186- case assign_risk ::domain_error:
70+ case conversion::risk::kind ::domain_error:
18771 return policy::error::kind::domain_error;
18872 default :
18973 return policy::error::kind::unspecified;
@@ -663,7 +547,7 @@ constexpr auto apply_assign(Lhs &lhs, Rhs const &rhs)
663547 if constexpr (std::same_as<lhs_value_policy, policy::value::checked> &&
664548 std_integer<lhs_rep> && std_numeric<common_rep>) {
665549 if (auto const kind =
666- details ::numeric_risk<lhs_rep>(assigned_common_rep);
550+ conversion ::numeric_risk<lhs_rep>(assigned_common_rep);
667551 kind.has_value ()) {
668552 return std::unexpected (
669553 details::to_error_payload<ErrorPayload>(
@@ -672,7 +556,7 @@ constexpr auto apply_assign(Lhs &lhs, Rhs const &rhs)
672556 }
673557
674558 auto const assigned_rep =
675- details::saturating_rep_cast <lhs_rep>(assigned_common_rep);
559+ conversion::saturating_cast <lhs_rep>(assigned_common_rep);
676560 lhs.store (underlying::traits<lhs_value_type>::from_rep (assigned_rep));
677561 return out;
678562}
0 commit comments