@@ -19,10 +19,6 @@ concept statically_castable = requires(SrcRep value) {
1919 static_cast <std::remove_cvref_t <DestRep>>(value);
2020};
2121
22- template <typename DestRep, typename SrcRep>
23- concept builtin_numeric_pair =
24- std_numeric<DestRep> && std_numeric<SrcRep>;
25-
2622template <underlying_type T>
2723using underlying_rep_t = underlying::traits<std::remove_cv_t <T>>::rep_type;
2824
@@ -75,123 +71,103 @@ struct floating_builtin_proxy {
7571template <typename Rep>
7672using floating_builtin_proxy_t = floating_builtin_proxy<Rep>::type;
7773
78- template <std_integer DestRep, std_integer SrcRep>
74+ template <std_numeric DestRep, std_numeric SrcRep>
7975constexpr auto numeric_risk (SrcRep value)
8076 -> std::optional<risk::kind> {
8177 using dest_type = std::remove_cvref_t <DestRep>;
8278 using src_type = std::remove_cvref_t <SrcRep>;
8379
84- if constexpr (std::is_signed_v<src_type>) {
85- auto const signed_value = static_cast <std::intmax_t >(value);
86- if constexpr (std::is_signed_v<dest_type>) {
87- if (signed_value <
88- static_cast <std::intmax_t >(std::numeric_limits<dest_type>::min ())) {
89- return risk::kind::underflow;
90- }
91- if (signed_value >
92- static_cast <std::intmax_t >(std::numeric_limits<dest_type>::max ())) {
93- return risk::kind::overflow;
80+ if constexpr (std_integer<dest_type> && std_integer<src_type>) {
81+ if constexpr (std::is_signed_v<src_type>) {
82+ auto const signed_value = static_cast <std::intmax_t >(value);
83+ if constexpr (std::is_signed_v<dest_type>) {
84+ if (signed_value <
85+ static_cast <std::intmax_t >(std::numeric_limits<dest_type>::min ())) {
86+ return risk::kind::underflow;
87+ }
88+ if (signed_value >
89+ static_cast <std::intmax_t >(std::numeric_limits<dest_type>::max ())) {
90+ return risk::kind::overflow;
91+ }
92+ return std::nullopt ;
93+ } else {
94+ if (signed_value < 0 ) {
95+ return risk::kind::underflow;
96+ }
97+
98+ if (static_cast <std::uintmax_t >(signed_value) >
99+ static_cast <std::uintmax_t >(
100+ std::numeric_limits<dest_type>::max ())) {
101+ return risk::kind::overflow;
102+ }
103+ return std::nullopt ;
94104 }
95- return std::nullopt ;
96105 } else {
97- if (signed_value < 0 ) {
98- return risk::kind::underflow;
99- }
100-
101- if (static_cast <std::uintmax_t >(signed_value) >
106+ auto const unsigned_value = static_cast <std::uintmax_t >(value);
107+ if (unsigned_value >
102108 static_cast <std::uintmax_t >(std::numeric_limits<dest_type>::max ())) {
103109 return risk::kind::overflow;
104110 }
105111 return std::nullopt ;
106112 }
107- } else {
108- auto const unsigned_value = static_cast <std::uintmax_t >(value);
109- if (unsigned_value >
110- static_cast <std::uintmax_t >(std::numeric_limits<dest_type>::max ())) {
111- return risk::kind::overflow;
113+ } else if constexpr (std_integer<dest_type> && std_floating<src_type>) {
114+ if (std::isnan (value)) {
115+ return risk::kind::domain_error;
116+ }
117+ if (std::isinf (value)) {
118+ return value < static_cast <src_type>(0 ) ? risk::kind::underflow
119+ : risk::kind::overflow;
112120 }
113- return std::nullopt ;
114- }
115- }
116-
117- template <std_integer DestRep, std_floating SrcRep>
118- constexpr auto numeric_risk (SrcRep value)
119- -> std::optional<risk::kind> {
120- using dest_type = std::remove_cvref_t <DestRep>;
121- using src_type = std::remove_cvref_t <SrcRep>;
122-
123- if (std::isnan (value)) {
124- return risk::kind::domain_error;
125- }
126- if (std::isinf (value)) {
127- return value < static_cast <src_type>(0 ) ? risk::kind::underflow
128- : risk::kind::overflow;
129- }
130-
131- auto const normalized = static_cast <long double >(value);
132- auto const min_value =
133- static_cast <long double >(std::numeric_limits<dest_type>::lowest ());
134- auto const max_value =
135- static_cast <long double >(std::numeric_limits<dest_type>::max ());
136-
137- if (normalized < min_value) {
138- return risk::kind::underflow;
139- }
140- if (normalized > max_value) {
141- return risk::kind::overflow;
142- }
143- return std::nullopt ;
144- }
145-
146- template <std_floating DestRep, std_integer SrcRep>
147- constexpr auto numeric_risk (SrcRep value)
148- -> std::optional<risk::kind> {
149- using dest_type = std::remove_cvref_t <DestRep>;
150- using src_type = std::remove_cvref_t <SrcRep>;
151-
152- auto const converted = static_cast <dest_type>(value);
153- if (std::isinf (converted)) {
154- return value < static_cast <src_type>(0 ) ? risk::kind::underflow
155- : risk::kind::overflow;
156- }
157-
158- auto const roundtrip = static_cast <src_type>(converted);
159- if (roundtrip != value) {
160- return risk::kind::precision_loss;
161- }
162121
163- return std::nullopt ;
164- }
122+ auto const normalized = static_cast <long double >(value);
123+ auto const min_value =
124+ static_cast <long double >(std::numeric_limits<dest_type>::lowest ());
125+ auto const max_value =
126+ static_cast <long double >(std::numeric_limits<dest_type>::max ());
165127
166- template <std_floating DestRep, std_floating SrcRep>
167- constexpr auto numeric_risk (SrcRep value)
168- -> std::optional<risk::kind> {
169- using dest_type = std::remove_cvref_t <DestRep>;
128+ if (normalized < min_value) {
129+ return risk::kind::underflow;
130+ }
131+ if (normalized > max_value) {
132+ return risk::kind::overflow;
133+ }
134+ } else if constexpr (std_floating<dest_type> && std_integer<src_type>) {
135+ auto const converted = static_cast <dest_type>(value);
136+ if (std::isinf (converted)) {
137+ return value < static_cast <src_type>(0 ) ? risk::kind::underflow
138+ : risk::kind::overflow;
139+ }
170140
171- if (std::isnan (value)) {
172- return std::nullopt ;
173- }
174- if (std::isinf (value)) {
175- return std::nullopt ;
176- }
141+ auto const roundtrip = static_cast <src_type>(converted);
142+ if (roundtrip != value) {
143+ return risk::kind::precision_loss;
144+ }
145+ } else {
146+ if (std::isnan (value)) {
147+ return std::nullopt ;
148+ }
149+ if (std::isinf (value)) {
150+ return std::nullopt ;
151+ }
177152
178- auto const normalized = static_cast <long double >(value);
179- auto const min_value =
180- static_cast <long double >(std::numeric_limits<dest_type>::lowest ());
181- auto const max_value =
182- static_cast <long double >(std::numeric_limits<dest_type>::max ());
153+ auto const normalized = static_cast <long double >(value);
154+ auto const min_value =
155+ static_cast <long double >(std::numeric_limits<dest_type>::lowest ());
156+ auto const max_value =
157+ static_cast <long double >(std::numeric_limits<dest_type>::max ());
183158
184- if (normalized < min_value) {
185- return risk::kind::underflow;
186- }
187- if (normalized > max_value) {
188- return risk::kind::overflow;
189- }
159+ if (normalized < min_value) {
160+ return risk::kind::underflow;
161+ }
162+ if (normalized > max_value) {
163+ return risk::kind::overflow;
164+ }
190165
191- auto const converted = static_cast <dest_type>(value);
192- auto const roundtrip = static_cast <std::remove_cvref_t <SrcRep>>(converted);
193- if (roundtrip != value) {
194- return risk::kind::precision_loss;
166+ auto const converted = static_cast <dest_type>(value);
167+ auto const roundtrip = static_cast <std::remove_cvref_t <SrcRep>>(converted);
168+ if (roundtrip != value) {
169+ return risk::kind::precision_loss;
170+ }
195171 }
196172
197173 return std::nullopt ;
@@ -238,7 +214,7 @@ constexpr auto checked_rep_cast(SrcRep value)
238214 using dest_type = std::remove_cvref_t <DestRep>;
239215 using src_type = std::remove_cvref_t <SrcRep>;
240216
241- if constexpr (builtin_numeric_pair <dest_type, src_type>) {
217+ if constexpr (std_numeric <dest_type> && std_numeric< src_type>) {
242218 if (auto const kind = numeric_risk<dest_type>(value); kind.has_value ()) {
243219 return std::unexpected (*kind);
244220 }
@@ -254,7 +230,7 @@ constexpr auto saturating_rep_cast(SrcRep value) noexcept
254230 using dest_type = std::remove_cvref_t <DestRep>;
255231 using src_type = std::remove_cvref_t <SrcRep>;
256232
257- if constexpr (builtin_numeric_pair <dest_type, src_type>) {
233+ if constexpr (std_numeric <dest_type> && std_numeric< src_type>) {
258234 if (auto const kind = numeric_risk<dest_type>(value); kind.has_value ()) {
259235 if (*kind == risk::kind::overflow) {
260236 return std::numeric_limits<dest_type>::max ();
@@ -312,7 +288,7 @@ constexpr auto exact_rep_cast(SrcRep value)
312288 using dest_type = std::remove_cvref_t <DestRep>;
313289 using src_type = std::remove_cvref_t <SrcRep>;
314290
315- if constexpr (!builtin_numeric_pair <dest_type, src_type>) {
291+ if constexpr (!(std_numeric <dest_type> && std_numeric< src_type>) ) {
316292 return std::unexpected (risk::kind::invalid_type_combination);
317293 } else {
318294 if (auto const kind = numeric_risk<dest_type>(value); kind.has_value ()) {
@@ -357,25 +333,7 @@ constexpr auto cast_underlying_result(Src value, RepCaster rep_caster)
357333
358334export namespace mcpplibs ::primitives::conversion {
359335
360- template <integer_underlying_type DestRep, integer_underlying_type SrcRep>
361- constexpr auto numeric_risk (SrcRep value)
362- -> std::optional<risk::kind> {
363- return details::numeric_underlying_risk<DestRep>(value);
364- }
365-
366- template <integer_underlying_type DestRep, floating_underlying_type SrcRep>
367- constexpr auto numeric_risk (SrcRep value)
368- -> std::optional<risk::kind> {
369- return details::numeric_underlying_risk<DestRep>(value);
370- }
371-
372- template <floating_underlying_type DestRep, integer_underlying_type SrcRep>
373- constexpr auto numeric_risk (SrcRep value)
374- -> std::optional<risk::kind> {
375- return details::numeric_underlying_risk<DestRep>(value);
376- }
377-
378- template <floating_underlying_type DestRep, floating_underlying_type SrcRep>
336+ template <numeric_underlying_type DestRep, numeric_underlying_type SrcRep>
379337constexpr auto numeric_risk (SrcRep value)
380338 -> std::optional<risk::kind> {
381339 return details::numeric_underlying_risk<DestRep>(value);
0 commit comments