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 :
14 : namespace fast_float {
15 :
16 :
17 : namespace detail {
18 : /**
19 : * Special case +inf, -inf, nan, infinity, -infinity.
20 : * The case comparisons could be made much faster given that we know that the
21 : * strings a null-free and fixed.
22 : **/
23 : template <typename T, typename UC>
24 : from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14
25 619 : parse_infnan(UC const * first, UC const * last, T &value) noexcept {
26 619 : from_chars_result_t<UC> answer{};
27 619 : answer.ptr = first;
28 619 : answer.ec = std::errc(); // be optimistic
29 619 : bool minusSign = false;
30 619 : if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
31 238 : minusSign = true;
32 238 : ++first;
33 : }
34 : #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
35 : if (*first == UC('+')) {
36 : ++first;
37 : }
38 : #endif
39 619 : if (last - first >= 3) {
40 5 : if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
41 0 : answer.ptr = (first += 3);
42 0 : value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
43 : // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
44 0 : if(first != last && *first == UC('(')) {
45 0 : for(UC const * ptr = first + 1; ptr != last; ++ptr) {
46 0 : if (*ptr == UC(')')) {
47 0 : answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
48 0 : break;
49 : }
50 0 : else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
51 0 : break; // forbidden char, not nan(n-char-seq-opt)
52 : }
53 : }
54 0 : return answer;
55 : }
56 5 : if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
57 0 : if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
58 0 : answer.ptr = first + 8;
59 : } else {
60 0 : answer.ptr = first + 3;
61 : }
62 0 : value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
63 0 : return answer;
64 : }
65 : }
66 619 : answer.ec = std::errc::invalid_argument;
67 619 : return answer;
68 : }
69 :
70 : /**
71 : * Returns true if the floating-pointing rounding mode is to 'nearest'.
72 : * It is the default on most system. This function is meant to be inexpensive.
73 : * Credit : @mwalcott3
74 : */
75 : fastfloat_really_inline bool rounds_to_nearest() noexcept {
76 : // https://lemire.me/blog/2020/06/26/gcc-not-nearest/
77 : #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
78 : return false;
79 : #endif
80 : // See
81 : // A fast function to check your floating-point rounding mode
82 : // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/
83 : //
84 : // This function is meant to be equivalent to :
85 : // prior: #include <cfenv>
86 : // return fegetround() == FE_TONEAREST;
87 : // However, it is expected to be much faster than the fegetround()
88 : // function call.
89 : //
90 : // The volatile keywoard prevents the compiler from computing the function
91 : // at compile-time.
92 : // There might be other ways to prevent compile-time optimizations (e.g., asm).
93 : // The value does not need to be std::numeric_limits<float>::min(), any small
94 : // value so that 1 + x should round to 1 would do (after accounting for excess
95 : // precision, as in 387 instructions).
96 : static volatile float fmin = std::numeric_limits<float>::min();
97 7358940 : float fmini = fmin; // we copy it so that it gets loaded at most once.
98 : //
99 : // Explanation:
100 : // Only when fegetround() == FE_TONEAREST do we have that
101 : // fmin + 1.0f == 1.0f - fmin.
102 : //
103 : // FE_UPWARD:
104 : // fmin + 1.0f > 1
105 : // 1.0f - fmin == 1
106 : //
107 : // FE_DOWNWARD or FE_TOWARDZERO:
108 : // fmin + 1.0f == 1
109 : // 1.0f - fmin < 1
110 : //
111 : // Note: This may fail to be accurate if fast-math has been
112 : // enabled, as rounding conventions may not apply.
113 : #ifdef FASTFLOAT_VISUAL_STUDIO
114 : # pragma warning(push)
115 : // todo: is there a VS warning?
116 : // see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
117 : #elif defined(__clang__)
118 : # pragma clang diagnostic push
119 : # pragma clang diagnostic ignored "-Wfloat-equal"
120 : #elif defined(__GNUC__)
121 : # pragma GCC diagnostic push
122 : # pragma GCC diagnostic ignored "-Wfloat-equal"
123 : #endif
124 7358940 : return (fmini + 1.0f == 1.0f - fmini);
125 : #ifdef FASTFLOAT_VISUAL_STUDIO
126 : # pragma warning(pop)
127 : #elif defined(__clang__)
128 : # pragma clang diagnostic pop
129 : #elif defined(__GNUC__)
130 : # pragma GCC diagnostic pop
131 : #endif
132 : }
133 :
134 : } // namespace detail
135 :
136 : template<typename T, typename UC>
137 : FASTFLOAT_CONSTEXPR20
138 224 : from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
139 : T &value, chars_format fmt /*= chars_format::general*/) noexcept {
140 224 : return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt});
141 : }
142 :
143 : template<typename T, typename UC>
144 : FASTFLOAT_CONSTEXPR20
145 7463760 : from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
146 : T &value, parse_options_t<UC> options) noexcept {
147 :
148 : static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
149 : static_assert (std::is_same<UC, char>::value ||
150 : std::is_same<UC, wchar_t>::value ||
151 : std::is_same<UC, char16_t>::value ||
152 : std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported");
153 :
154 : from_chars_result_t<UC> answer;
155 : #ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
156 : while ((first != last) && fast_float::is_space(uint8_t(*first))) {
157 : first++;
158 : }
159 : #endif
160 7463760 : if (first == last) {
161 40491 : answer.ec = std::errc::invalid_argument;
162 40491 : answer.ptr = first;
163 40491 : return answer;
164 : }
165 7423270 : parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
166 7423270 : if (!pns.valid) {
167 619 : if (options.format & chars_format::no_infnan) {
168 0 : answer.ec = std::errc::invalid_argument;
169 0 : answer.ptr = first;
170 0 : return answer;
171 : } else {
172 619 : return detail::parse_infnan(first, last, value);
173 : }
174 : }
175 :
176 7422650 : answer.ec = std::errc(); // be optimistic
177 7422650 : answer.ptr = pns.lastmatch;
178 : // The implementation of the Clinger's fast path is convoluted because
179 : // we want round-to-nearest in all cases, irrespective of the rounding mode
180 : // selected on the thread.
181 : // We proceed optimistically, assuming that detail::rounds_to_nearest() returns
182 : // true.
183 7422650 : if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && !pns.too_many_digits) {
184 : // Unfortunately, the conventional Clinger's fast path is only possible
185 : // when the system rounds to the nearest float.
186 : //
187 : // We expect the next branch to almost always be selected.
188 : // We could check it first (before the previous branch), but
189 : // there might be performance advantages at having the check
190 : // be last.
191 14717900 : if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
192 : // We have that fegetround() == FE_TONEAREST.
193 : // Next is Clinger's fast path.
194 7358940 : if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
195 7156000 : value = T(pns.mantissa);
196 7156000 : if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
197 1110970 : else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
198 7156000 : if (pns.negative) { value = -value; }
199 7156000 : return answer;
200 : }
201 : } else {
202 : // We do not have that fegetround() == FE_TONEAREST.
203 : // Next is a modified Clinger's fast path, inspired by Jakub JelĂnek's proposal
204 0 : if (pns.exponent >= 0 && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
205 : #if defined(__clang__)
206 : // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
207 : if(pns.mantissa == 0) {
208 : value = pns.negative ? -0. : 0.;
209 : return answer;
210 : }
211 : #endif
212 0 : value = T(pns.mantissa) * binary_format<T>::exact_power_of_ten(pns.exponent);
213 0 : if (pns.negative) { value = -value; }
214 0 : return answer;
215 : }
216 : }
217 : }
218 266645 : adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
219 266645 : if(pns.too_many_digits && am.power2 >= 0) {
220 125032 : if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
221 0 : am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
222 : }
223 : }
224 : // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
225 : // then we need to go the long way around again. This is very uncommon.
226 266645 : if(am.power2 < 0) { am = digit_comp<T>(pns, am); }
227 266645 : to_float(pns.negative, am, value);
228 : // Test for over/underflow.
229 266645 : if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format<T>::infinite_power()) {
230 3 : answer.ec = std::errc::result_out_of_range;
231 : }
232 266645 : return answer;
233 : }
234 :
235 : } // namespace fast_float
236 :
237 : #endif
|