18
18
#include < charconv>
19
19
#include < concepts>
20
20
#include < limits>
21
- #include < cstring>
22
21
#include < type_traits>
23
22
24
23
// Included for the _Floating_type_traits class
@@ -36,9 +35,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
36
35
// - __ptr is the current position is the input string. This is points beyond
37
36
// the initial I character.
38
37
// - __negative whether a valid string represents -inf or +inf.
39
- template <floating_point _Tp >
38
+ template <floating_point _Fp >
40
39
from_chars_result __from_chars_floating_point_inf (
41
- const char * const __first, const char * __last, _Tp & __value, const char * __ptr, bool __negative) {
40
+ const char * const __first, const char * __last, _Fp & __value, const char * __ptr, bool __negative) {
42
41
if (__last - __ptr < 2 ) [[unlikely]]
43
42
return {__first, errc::invalid_argument};
44
43
@@ -60,19 +59,19 @@ from_chars_result __from_chars_floating_point_inf(
60
59
&& std::tolower (__ptr[4 ]) == ' y' )
61
60
__ptr += 5 ;
62
61
63
- if constexpr (numeric_limits<_Tp >::has_infinity) {
62
+ if constexpr (numeric_limits<_Fp >::has_infinity) {
64
63
if (__negative)
65
- __value = -std::numeric_limits<_Tp >::infinity ();
64
+ __value = -std::numeric_limits<_Fp >::infinity ();
66
65
else
67
- __value = std::numeric_limits<_Tp >::infinity ();
66
+ __value = std::numeric_limits<_Fp >::infinity ();
68
67
69
68
return {__ptr, std::errc{}};
70
69
} else {
71
70
return {__ptr, errc::result_out_of_range};
72
71
}
73
72
}
74
73
75
- // Parses an infinita string.
74
+ // Parses a nan string.
76
75
// Valid strings are case insentitive and contain INF or INFINITY.
77
76
//
78
77
// - __first is the first argument to std::from_chars. When the string is invalid
@@ -82,9 +81,9 @@ from_chars_result __from_chars_floating_point_inf(
82
81
// - __ptr is the current position is the input string. This is points beyond
83
82
// the initial N character.
84
83
// - __negative whether a valid string represents -nan or +nan.
85
- template <floating_point _Tp >
84
+ template <floating_point _Fp >
86
85
from_chars_result __from_chars_floating_point_nan (
87
- const char * const __first, const char * __last, _Tp & __value, const char * __ptr, bool __negative) {
86
+ const char * const __first, const char * __last, _Fp & __value, const char * __ptr, bool __negative) {
88
87
if (__last - __ptr < 2 ) [[unlikely]]
89
88
return {__first, errc::invalid_argument};
90
89
@@ -111,32 +110,33 @@ from_chars_result __from_chars_floating_point_nan(
111
110
}
112
111
113
112
if (__negative)
114
- __value = -std::numeric_limits<_Tp >::quiet_NaN ();
113
+ __value = -std::numeric_limits<_Fp >::quiet_NaN ();
115
114
else
116
- __value = std::numeric_limits<_Tp >::quiet_NaN ();
115
+ __value = std::numeric_limits<_Fp >::quiet_NaN ();
117
116
118
117
return {__ptr, std::errc{}};
119
118
}
120
119
121
- template <floating_point _Tp >
120
+ template <floating_point _Fp >
122
121
from_chars_result __from_chars_floating_point_decimal (
123
122
const char * const __first,
124
123
const char * __last,
125
- _Tp & __value,
124
+ _Fp & __value,
126
125
chars_format __fmt,
127
126
const char * __ptr,
128
127
bool __negative) {
129
- using _Traits = _Floating_type_traits<_Tp >;
128
+ using _Traits = _Floating_type_traits<_Fp >;
130
129
using _Uint_type = typename _Traits::_Uint_type;
131
- ptrdiff_t length = __last - __first;
132
- _LIBCPP_ASSERT_INTERNAL (length > 0 , " " );
133
130
134
- const char * src = __ptr; // rename to match the libc code copied for this section.
131
+ const char * src = __ptr; // rename to match the libc code copied for this section.
132
+ ptrdiff_t length = __last - src;
133
+ _LIBCPP_ASSERT_INTERNAL (length > 0 , " " );
135
134
136
135
_Uint_type mantissa = 0 ;
137
136
int exponent = 0 ;
138
137
bool truncated = false ;
139
138
bool seen_digit = false ;
139
+ bool has_valid_exponent = false ;
140
140
bool after_decimal = false ;
141
141
size_t index = 0 ;
142
142
const size_t BASE = 10 ;
@@ -145,6 +145,7 @@ from_chars_result __from_chars_floating_point_decimal(
145
145
146
146
// The loop fills the mantissa with as many digits as it can hold
147
147
const _Uint_type bitstype_max_div_by_base = numeric_limits<_Uint_type>::max () / BASE;
148
+
148
149
while (index < static_cast <size_t >(length)) {
149
150
if (LIBC_NAMESPACE::internal::isdigit (src[index ])) {
150
151
uint32_t digit = src[index ] - ' 0' ;
@@ -178,7 +179,7 @@ from_chars_result __from_chars_floating_point_decimal(
178
179
}
179
180
180
181
if (!seen_digit)
181
- return {src + index , {} };
182
+ return {__first, errc::invalid_argument };
182
183
183
184
if (index < static_cast <size_t >(length) && LIBC_NAMESPACE::internal::tolower (src[index ]) == EXPONENT_MARKER) {
184
185
bool has_sign = false ;
@@ -187,8 +188,10 @@ from_chars_result __from_chars_floating_point_decimal(
187
188
}
188
189
if (index + 1 + static_cast <size_t >(has_sign) < static_cast <size_t >(length) &&
189
190
LIBC_NAMESPACE::internal::isdigit (src[index + 1 + static_cast <size_t >(has_sign)])) {
191
+ has_valid_exponent = true ;
190
192
++index ;
191
- auto result = LIBC_NAMESPACE::internal::strtointeger<int32_t >(src + index , 10 );
193
+ auto result =
194
+ LIBC_NAMESPACE::internal::strtointeger<int32_t >(src + index , 10 , static_cast <size_t >(length) - index );
192
195
// if (result.has_error())
193
196
// output.error = result.error;
194
197
int32_t add_to_exponent = result.value ;
@@ -199,57 +202,102 @@ from_chars_result __from_chars_floating_point_decimal(
199
202
200
203
// If the result is in the valid range, then we use it. The valid range is
201
204
// also within the int32 range, so this prevents overflow issues.
202
- if (temp_exponent > LIBC_NAMESPACE::fputil::FPBits<_Tp >::MAX_BIASED_EXPONENT) {
203
- exponent = LIBC_NAMESPACE::fputil::FPBits<_Tp >::MAX_BIASED_EXPONENT;
204
- } else if (temp_exponent < -LIBC_NAMESPACE::fputil::FPBits<_Tp >::MAX_BIASED_EXPONENT) {
205
- exponent = -LIBC_NAMESPACE::fputil::FPBits<_Tp >::MAX_BIASED_EXPONENT;
205
+ if (temp_exponent > LIBC_NAMESPACE::fputil::FPBits<_Fp >::MAX_BIASED_EXPONENT) {
206
+ exponent = LIBC_NAMESPACE::fputil::FPBits<_Fp >::MAX_BIASED_EXPONENT;
207
+ } else if (temp_exponent < -LIBC_NAMESPACE::fputil::FPBits<_Fp >::MAX_BIASED_EXPONENT) {
208
+ exponent = -LIBC_NAMESPACE::fputil::FPBits<_Fp >::MAX_BIASED_EXPONENT;
206
209
} else {
207
210
exponent = static_cast <int32_t >(temp_exponent);
208
211
}
209
212
}
210
213
}
211
214
212
- LIBC_NAMESPACE::internal::ExpandedFloat<_Tp> expanded_float = {0 , 0 };
215
+ // [charconv.from.chars]
216
+ switch (__fmt) {
217
+ case chars_format::scientific:
218
+ // 6.2 if fmt has chars_format::scientific set but not chars_format::fixed,
219
+ // the otherwise optional exponent part shall appear;
220
+ if (!has_valid_exponent)
221
+ return {__first, errc::invalid_argument};
222
+ break ;
223
+ case chars_format::fixed:
224
+ // 6.3 if fmt has chars_format::fixed set but not chars_format::scientific,
225
+ // the optional exponent part shall not appear;
226
+ if (has_valid_exponent)
227
+ return {__first, errc::invalid_argument};
228
+ break ;
229
+ case chars_format::general:
230
+ case chars_format::hex: // impossible but it silences the compiler
231
+ break ;
232
+ }
233
+
234
+ LIBC_NAMESPACE::internal::ExpandedFloat<_Fp> expanded_float = {0 , 0 };
235
+ errc status{};
213
236
if (mantissa != 0 ) {
214
- auto temp = LIBC_NAMESPACE::shared::decimal_exp_to_float<_Tp >(
237
+ auto temp = LIBC_NAMESPACE::shared::decimal_exp_to_float<_Fp >(
215
238
{mantissa, exponent}, truncated, LIBC_NAMESPACE::internal::RoundDirection::Nearest, src, length);
216
239
expanded_float = temp.num ;
217
- // Note: there's also an error value in temp.error. I'm not doing that error handling right now though.
240
+ if (temp.error == ERANGE) {
241
+ status = errc::result_out_of_range;
242
+ }
218
243
}
219
244
220
- auto result = LIBC_NAMESPACE::fputil::FPBits<_Tp >();
245
+ auto result = LIBC_NAMESPACE::fputil::FPBits<_Fp >();
221
246
result.set_mantissa (expanded_float.mantissa );
222
247
result.set_biased_exponent (expanded_float.exponent );
248
+
249
+ // C17 7.12.1/6
250
+ // The result underflows if the magnitude of the mathematical result is so
251
+ // small that the mathematical re- sult cannot be represented, without
252
+ // extraordinary roundoff error, in an object of the specified type.237) If
253
+ // the result underflows, the function returns an implementation-defined
254
+ // value whose magnitude is no greater than the smallest normalized positive
255
+ // number in the specified type; if the integer expression math_errhandling
256
+ // & MATH_ERRNO is nonzero, whether errno acquires the value ERANGE is
257
+ // implementation-defined; if the integer expression math_errhandling &
258
+ // MATH_ERREXCEPT is nonzero, whether the "underflow" floating-point
259
+ // exception is raised is implementation-defined.
260
+ //
261
+ // LLLVM-LIBC sets ERAGNE for subnormal values
262
+ //
263
+ // [charconv.from.chars]/1
264
+ // ... If the parsed value is not in the range representable by the type of
265
+ // value, value is unmodified and the member ec of the return value is
266
+ // equal to errc::result_out_of_range. ...
267
+ //
268
+ // Undo the ERANGE for subnormal values.
269
+ if (status == errc::result_out_of_range && result.is_subnormal () && !result.is_zero ())
270
+ status = errc{};
271
+
223
272
if (__negative)
224
273
__value = -result.get_val ();
225
274
else
226
275
__value = result.get_val ();
227
- return {src + index , {}};
276
+
277
+ return {src + index , status};
228
278
}
229
279
230
- template <floating_point _Tp >
280
+ template <floating_point _Fp >
231
281
from_chars_result
232
- __from_chars_floating_point (const char * const __first, const char * __last, _Tp & __value, chars_format __fmt) {
282
+ __from_chars_floating_point (const char * const __first, const char * __last, _Fp & __value, chars_format __fmt) {
233
283
if (__first == __last) [[unlikely]]
234
284
return {__first, errc::invalid_argument};
235
285
236
286
const char * __ptr = __first;
237
-
238
- // skip whitespace
239
- while (std::isspace (*__ptr)) {
240
- ++__ptr;
241
- if (__ptr == __last) [[unlikely]]
242
- return {__first, errc::invalid_argument}; // is this valid??
243
- }
244
-
245
- bool __negative = *__ptr == ' -' ;
287
+ bool __negative = *__ptr == ' -' ;
246
288
if (__negative) {
247
289
++__ptr;
248
290
if (__ptr == __last) [[unlikely]]
249
291
return {__first, errc::invalid_argument};
250
292
}
251
293
252
- if (!std::isdigit (*__ptr)) {
294
+ // [charconv.from.chars]
295
+ // [Note 1: If the pattern allows for an optional sign, but the string has
296
+ // no digit characters following the sign, no characters match the pattern.
297
+ // — end note]
298
+ // This is true for integrals, floating point allows -.0
299
+ switch (std::tolower (*__ptr)) {
300
+ case ' i' :
253
301
// TODO Evaluate the other implementations
254
302
// [charconv.from.chars]/6.2
255
303
// if fmt has chars_format::scientific set but not chars_format::fixed,
@@ -259,20 +307,23 @@ __from_chars_floating_point(const char* const __first, const char* __last, _Tp&
259
307
if (__fmt == chars_format::scientific)
260
308
return {__first, errc::invalid_argument};
261
309
262
- switch (std::tolower (*__ptr)) {
263
- case ' i' :
264
- return __from_chars_floating_point_inf (__first, __last, __value, __ptr + 1 , __negative);
265
- case ' n' :
266
- if constexpr (numeric_limits<_Tp>::has_quiet_NaN)
267
- return __from_chars_floating_point_nan (__first, __last, __value, __ptr + 1 , __negative);
268
- [[fallthrough]];
269
- default :
310
+ return __from_chars_floating_point_inf (__first, __last, __value, __ptr + 1 , __negative);
311
+ case ' n' :
312
+ // TODO Evaluate the other implementations
313
+ // [charconv.from.chars]/6.2
314
+ // if fmt has chars_format::scientific set but not chars_format::fixed,
315
+ // the otherwise optional exponent part shall appear;
316
+ // Since INF/NAN do not have an exponent this value is not valid.
317
+ // See LWG3456
318
+ if (__fmt == chars_format::scientific)
270
319
return {__first, errc::invalid_argument};
271
- }
320
+ if constexpr (numeric_limits<_Fp>::has_quiet_NaN)
321
+ return __from_chars_floating_point_nan (__first, __last, __value, __ptr + 1 , __negative);
322
+ return {__first, errc::invalid_argument};
272
323
}
273
324
274
325
#if 1
275
- _LIBCPP_ASSERT_INTERNAL (__fmt == std::chars_format::general , " " );
326
+ _LIBCPP_ASSERT_INTERNAL (__fmt != std::chars_format::hex , " " );
276
327
#else
277
328
if (__fmt == chars_format::hex)
278
329
return std::__from_chars_floating_point_hex(__first, __last, __value);
0 commit comments