Skip to content

Commit 988227e

Browse files
refactor: Update numeric risk handling to support broader numeric types and improve type safety
Signed-off-by: FrozenlemonTee <1115306170@qq.com>
1 parent b29f427 commit 988227e

1 file changed

Lines changed: 82 additions & 124 deletions

File tree

src/conversion/underlying.cppm

Lines changed: 82 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
2622
template <underlying_type T>
2723
using underlying_rep_t = underlying::traits<std::remove_cv_t<T>>::rep_type;
2824

@@ -75,123 +71,103 @@ struct floating_builtin_proxy {
7571
template <typename Rep>
7672
using 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>
7975
constexpr 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

358334
export 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>
379337
constexpr auto numeric_risk(SrcRep value)
380338
-> std::optional<risk::kind> {
381339
return details::numeric_underlying_risk<DestRep>(value);

0 commit comments

Comments
 (0)