Line data Source code
1 : #ifndef FASTFLOAT_PARSE_NUMBER_H
2 : #define FASTFLOAT_PARSE_NUMBER_H
3 :
4 : #include "ascii_number.h"
5 : #include "decimal_to_binary.h"
6 : #include "digit_comparison.h"
7 : #include "float_common.h"
8 :
9 : #include <cmath>
10 : #include <cstring>
11 : #include <limits>
12 : #include <system_error>
13 : namespace fast_float {
14 :
15 : namespace detail {
16 : /**
17 : * Special case +inf, -inf, nan, infinity, -infinity.
18 : * The case comparisons could be made much faster given that we know that the
19 : * strings a null-free and fixed.
20 : **/
21 : template <typename T, typename UC>
22 662 : from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first,
23 : UC const *last,
24 : T &value) noexcept {
25 662 : from_chars_result_t<UC> answer{};
26 662 : answer.ptr = first;
27 662 : answer.ec = std::errc(); // be optimistic
28 662 : bool minusSign = false;
29 662 : if (*first ==
30 : UC('-')) { // assume first < last, so dereference without checks;
31 : // C++17 20.19.3.(7.1) explicitly forbids '+' here
32 252 : minusSign = true;
33 252 : ++first;
34 : }
35 : #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
36 : if (*first == UC('+')) {
37 : ++first;
38 : }
39 : #endif
40 662 : if (last - first >= 3) {
41 5 : if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
42 0 : answer.ptr = (first += 3);
43 0 : value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
44 0 : : std::numeric_limits<T>::quiet_NaN();
45 : // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7,
46 : // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
47 0 : if (first != last && *first == UC('(')) {
48 0 : for (UC const *ptr = first + 1; ptr != last; ++ptr) {
49 0 : if (*ptr == UC(')')) {
50 0 : answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
51 0 : break;
52 0 : } else if (!((UC('a') <= *ptr && *ptr <= UC('z')) ||
53 0 : (UC('A') <= *ptr && *ptr <= UC('Z')) ||
54 0 : (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
55 0 : break; // forbidden char, not nan(n-char-seq-opt)
56 : }
57 : }
58 0 : return answer;
59 : }
60 5 : if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
61 0 : if ((last - first >= 8) &&
62 0 : fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
63 0 : answer.ptr = first + 8;
64 : } else {
65 0 : answer.ptr = first + 3;
66 : }
67 0 : value = minusSign ? -std::numeric_limits<T>::infinity()
68 0 : : std::numeric_limits<T>::infinity();
69 0 : return answer;
70 : }
71 : }
72 662 : answer.ec = std::errc::invalid_argument;
73 662 : return answer;
74 : }
75 :
76 : /**
77 : * Returns true if the floating-pointing rounding mode is to 'nearest'.
78 : * It is the default on most system. This function is meant to be inexpensive.
79 : * Credit : @mwalcott3
80 : */
81 : fastfloat_really_inline bool rounds_to_nearest() noexcept {
82 : // https://lemire.me/blog/2020/06/26/gcc-not-nearest/
83 : #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
84 : return false;
85 : #endif
86 : // See
87 : // A fast function to check your floating-point rounding mode
88 : // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/
89 : //
90 : // This function is meant to be equivalent to :
91 : // prior: #include <cfenv>
92 : // return fegetround() == FE_TONEAREST;
93 : // However, it is expected to be much faster than the fegetround()
94 : // function call.
95 : //
96 : // The volatile keywoard prevents the compiler from computing the function
97 : // at compile-time.
98 : // There might be other ways to prevent compile-time optimizations (e.g.,
99 : // asm). The value does not need to be std::numeric_limits<float>::min(), any
100 : // small value so that 1 + x should round to 1 would do (after accounting for
101 : // excess precision, as in 387 instructions).
102 : static volatile float fmin = std::numeric_limits<float>::min();
103 15170400 : float fmini = fmin; // we copy it so that it gets loaded at most once.
104 : //
105 : // Explanation:
106 : // Only when fegetround() == FE_TONEAREST do we have that
107 : // fmin + 1.0f == 1.0f - fmin.
108 : //
109 : // FE_UPWARD:
110 : // fmin + 1.0f > 1
111 : // 1.0f - fmin == 1
112 : //
113 : // FE_DOWNWARD or FE_TOWARDZERO:
114 : // fmin + 1.0f == 1
115 : // 1.0f - fmin < 1
116 : //
117 : // Note: This may fail to be accurate if fast-math has been
118 : // enabled, as rounding conventions may not apply.
119 : #ifdef FASTFLOAT_VISUAL_STUDIO
120 : #pragma warning(push)
121 : // todo: is there a VS warning?
122 : // see
123 : // https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
124 : #elif defined(__clang__)
125 : #pragma clang diagnostic push
126 : #pragma clang diagnostic ignored "-Wfloat-equal"
127 : #elif defined(__GNUC__)
128 : #pragma GCC diagnostic push
129 : #pragma GCC diagnostic ignored "-Wfloat-equal"
130 : #endif
131 15170400 : return (fmini + 1.0f == 1.0f - fmini);
132 : #ifdef FASTFLOAT_VISUAL_STUDIO
133 : #pragma warning(pop)
134 : #elif defined(__clang__)
135 : #pragma clang diagnostic pop
136 : #elif defined(__GNUC__)
137 : #pragma GCC diagnostic pop
138 : #endif
139 : }
140 :
141 : } // namespace detail
142 :
143 : template <typename T> struct from_chars_caller {
144 : template <typename UC>
145 : FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
146 224 : call(UC const *first, UC const *last, T &value,
147 : parse_options_t<UC> options) noexcept {
148 224 : return from_chars_advanced(first, last, value, options);
149 : }
150 : };
151 :
152 : #if __STDCPP_FLOAT32_T__ == 1
153 : template <> struct from_chars_caller<std::float32_t> {
154 : template <typename UC>
155 : FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
156 : call(UC const *first, UC const *last, std::float32_t &value,
157 : parse_options_t<UC> options) noexcept {
158 : // if std::float32_t is defined, and we are in C++23 mode; macro set for
159 : // float32; set value to float due to equivalence between float and
160 : // float32_t
161 : float val;
162 : auto ret = from_chars_advanced(first, last, val, options);
163 : value = val;
164 : return ret;
165 : }
166 : };
167 : #endif
168 :
169 : #if __STDCPP_FLOAT64_T__ == 1
170 : template <> struct from_chars_caller<std::float64_t> {
171 : template <typename UC>
172 : FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
173 : call(UC const *first, UC const *last, std::float64_t &value,
174 : parse_options_t<UC> options) noexcept {
175 : // if std::float64_t is defined, and we are in C++23 mode; macro set for
176 : // float64; set value as double due to equivalence between double and
177 : // float64_t
178 : double val;
179 : auto ret = from_chars_advanced(first, last, val, options);
180 : value = val;
181 : return ret;
182 : }
183 : };
184 : #endif
185 :
186 : template <typename T, typename UC, typename>
187 : FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
188 224 : from_chars(UC const *first, UC const *last, T &value,
189 : chars_format fmt /*= chars_format::general*/) noexcept {
190 448 : return from_chars_caller<T>::call(first, last, value,
191 224 : parse_options_t<UC>(fmt));
192 : }
193 :
194 : /**
195 : * This function overload takes parsed_number_string_t structure that is created
196 : * and populated either by from_chars_advanced function taking chars range and
197 : * parsing options or other parsing custom function implemented by user.
198 : */
199 : template <typename T, typename UC>
200 : FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
201 15234200 : from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
202 :
203 : static_assert(is_supported_float_type<T>(),
204 : "only some floating-point types are supported");
205 : static_assert(is_supported_char_type<UC>(),
206 : "only char, wchar_t, char16_t and char32_t are supported");
207 :
208 : from_chars_result_t<UC> answer;
209 :
210 15234200 : answer.ec = std::errc(); // be optimistic
211 15234200 : answer.ptr = pns.lastmatch;
212 : // The implementation of the Clinger's fast path is convoluted because
213 : // we want round-to-nearest in all cases, irrespective of the rounding mode
214 : // selected on the thread.
215 : // We proceed optimistically, assuming that detail::rounds_to_nearest()
216 : // returns true.
217 15234200 : if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
218 30467200 : pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
219 15233000 : !pns.too_many_digits) {
220 : // Unfortunately, the conventional Clinger's fast path is only possible
221 : // when the system rounds to the nearest float.
222 : //
223 : // We expect the next branch to almost always be selected.
224 : // We could check it first (before the previous branch), but
225 : // there might be performance advantages at having the check
226 : // be last.
227 30340900 : if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
228 : // We have that fegetround() == FE_TONEAREST.
229 : // Next is Clinger's fast path.
230 15170400 : if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
231 14966700 : value = T(pns.mantissa);
232 14966700 : if (pns.exponent < 0) {
233 13589200 : value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
234 : } else {
235 1377570 : value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
236 : }
237 14966700 : if (pns.negative) {
238 6472000 : value = -value;
239 : }
240 14966700 : return answer;
241 : }
242 : } else {
243 : // We do not have that fegetround() == FE_TONEAREST.
244 : // Next is a modified Clinger's fast path, inspired by Jakub JelĂnek's
245 : // proposal
246 0 : if (pns.exponent >= 0 &&
247 0 : pns.mantissa <=
248 0 : binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
249 : #if defined(__clang__) || defined(FASTFLOAT_32BIT)
250 : // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
251 : if (pns.mantissa == 0) {
252 : value = pns.negative ? T(-0.) : T(0.);
253 : return answer;
254 : }
255 : #endif
256 0 : value = T(pns.mantissa) *
257 0 : binary_format<T>::exact_power_of_ten(pns.exponent);
258 0 : if (pns.negative) {
259 0 : value = -value;
260 : }
261 0 : return answer;
262 : }
263 : }
264 : }
265 : adjusted_mantissa am =
266 267453 : compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
267 267452 : if (pns.too_many_digits && am.power2 >= 0) {
268 125182 : if (am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
269 0 : am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
270 : }
271 : }
272 : // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa)
273 : // and we have an invalid power (am.power2 < 0), then we need to go the long
274 : // way around again. This is very uncommon.
275 267452 : if (am.power2 < 0) {
276 0 : am = digit_comp<T>(pns, am);
277 : }
278 267452 : to_float(pns.negative, am, value);
279 : // Test for over/underflow.
280 534904 : if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) ||
281 267452 : am.power2 == binary_format<T>::infinite_power()) {
282 3 : answer.ec = std::errc::result_out_of_range;
283 : }
284 267452 : return answer;
285 : }
286 :
287 : template <typename T, typename UC>
288 : FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
289 15276000 : from_chars_advanced(UC const *first, UC const *last, T &value,
290 : parse_options_t<UC> options) noexcept {
291 :
292 : static_assert(is_supported_float_type<T>(),
293 : "only some floating-point types are supported");
294 : static_assert(is_supported_char_type<UC>(),
295 : "only char, wchar_t, char16_t and char32_t are supported");
296 :
297 : from_chars_result_t<UC> answer;
298 : #ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
299 : while ((first != last) && fast_float::is_space(uint8_t(*first))) {
300 : first++;
301 : }
302 : #endif
303 15276000 : if (first == last) {
304 41110 : answer.ec = std::errc::invalid_argument;
305 41110 : answer.ptr = first;
306 41110 : return answer;
307 : }
308 : parsed_number_string_t<UC> pns =
309 15234800 : parse_number_string<UC>(first, last, options);
310 15234800 : if (!pns.valid) {
311 662 : if (options.format & chars_format::no_infnan) {
312 0 : answer.ec = std::errc::invalid_argument;
313 0 : answer.ptr = first;
314 0 : return answer;
315 : } else {
316 662 : return detail::parse_infnan(first, last, value);
317 : }
318 : }
319 :
320 : // call overload that takes parsed_number_string_t directly.
321 15234200 : return from_chars_advanced(pns, value);
322 : }
323 :
324 : template <typename T, typename UC, typename>
325 : FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
326 : from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
327 : static_assert(is_supported_char_type<UC>(),
328 : "only char, wchar_t, char16_t and char32_t are supported");
329 :
330 : from_chars_result_t<UC> answer;
331 : #ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
332 : while ((first != last) && fast_float::is_space(uint8_t(*first))) {
333 : first++;
334 : }
335 : #endif
336 : if (first == last || base < 2 || base > 36) {
337 : answer.ec = std::errc::invalid_argument;
338 : answer.ptr = first;
339 : return answer;
340 : }
341 : return parse_int_string(first, last, value, base);
342 : }
343 :
344 : } // namespace fast_float
345 :
346 : #endif
|