34 namespace json_details {
35 template<
bool skip_end_check,
typename Un
signed>
36 DAW_ATTRIB_FLATINLINE
constexpr void
37 parse_digits_until_last( daw::not_null<char const *> first,
38 daw::not_null<char const *>
const last,
39 Unsigned &DAW_RESTRICT v ) {
41 if constexpr( skip_end_check ) {
42 auto dig = parse_digit( *first );
47 dig = parse_digit( *first );
50 while( DAW_LIKELY( first < last ) ) {
52 value += parse_digit( *first );
59 template<
bool skip_end_check,
typename Un
signed>
60 [[nodiscard]] DAW_ATTRIB_FLATINLINE
constexpr daw::not_null<char const *>
61 parse_digits_while_number( daw::not_null<char const *> first,
62 daw::not_null<char const *>
const last,
63 Unsigned &DAW_RESTRICT v ) {
70 if constexpr( skip_end_check ) {
71 for(
auto dig = parse_digit( *first ); dig < 10U;
72 ++first, dig = parse_digit( *first ) ) {
78 auto dig = parse_digit( *first );
83 if( DAW_UNLIKELY( first == last ) ) {
86 dig = parse_digit( *first );
96 template<
typename ParseState,
typename Result,
97 typename max_storage_digits>
98 [[nodiscard]]
constexpr bool
99 should_use_strtod( daw::not_null<char const *> whole_first,
100 daw::not_null<char const *>
const whole_last,
101 char const *fract_first,
char const *fract_last ) {
102 if constexpr( std::is_floating_point_v<Result> and
103 ParseState::precise_ieee754 ) {
105 ( ( whole_last - whole_first ) +
106 ( fract_first ? fract_last - fract_first : 0 ) ) >
107 max_storage_digits::value );
118 template<
typename Result,
typename ParseState>
119 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
120 parse_real_known( ParseState &parse_state ) {
123 parse_state.has_more( ) and
124 parse_policy_details::is_number_start( parse_state.front( ) ),
125 ErrorReason::InvalidNumberStart,
128 daw::not_null<char const *> whole_first = parse_state.first;
129 char const *whole_last = parse_state.class_first
130 ? parse_state.class_first
131 : parse_state.class_last;
132 char const *fract_first =
133 parse_state.class_first ? parse_state.class_first + 1 :
nullptr;
134 char const *fract_last = parse_state.class_last;
135 char const *exp_first =
136 parse_state.class_last ? parse_state.class_last + 1 :
nullptr;
137 daw::not_null<char const *>
const exp_last = parse_state.last;
139 if( parse_state.class_first ==
nullptr ) {
140 if( parse_state.class_last ==
nullptr ) {
141 whole_last = parse_state.last;
143 whole_last = parse_state.class_last;
145 }
else if( parse_state.class_last ==
nullptr ) {
146 fract_last = parse_state.last;
149 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
150 daw::digits10<std::uint64_t> )>;
153 should_use_strtod<ParseState, Result, max_storage_digits>(
154 whole_first, whole_last, fract_first, fract_last );
156 Result
const sign = [&] {
157 if( *whole_first ==
'-' ) {
159 return static_cast<Result
>( -1.0 );
161 return static_cast<Result
>( 1.0 );
163 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
164 daw::max_digits10<Result> + 1 )>;
166 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
171 typename daw::conditional_t<std::is_floating_point_v<unsigned_t>,
172 daw::traits::identity<unsigned_t>,
173 std::make_signed<unsigned_t>>::type;
174 std::intmax_t whole_exponent_available = whole_last - whole_first;
175 std::intmax_t fract_exponent_available =
176 fract_first ? fract_last - fract_first : 0;
177 signed_t exponent = 0;
179 if( whole_exponent_available > max_exponent::value ) {
180 whole_last = whole_first + max_exponent::value;
181 whole_exponent_available -= max_exponent::value;
182 fract_exponent_available = 0;
183 fract_first =
nullptr;
184 exponent = whole_exponent_available;
186 whole_exponent_available =
187 max_exponent::value - whole_exponent_available;
188 if constexpr( ParseState::precise_ieee754 ) {
189 use_strtod |= DAW_UNLIKELY( fract_exponent_available >
190 whole_exponent_available );
192 if( whole_exponent_available < fract_exponent_available ) {
193 fract_exponent_available = whole_exponent_available;
195 exponent = -fract_exponent_available;
196 fract_last = fract_first + fract_exponent_available;
199 unsigned_t significant_digits = 0;
200 parse_digits_until_last<( ParseState::is_zero_terminated_string or
201 ParseState::is_unchecked_input )>(
202 whole_first, whole_last, significant_digits );
204 parse_digits_until_last<( ParseState::is_zero_terminated_string or
205 ParseState::is_unchecked_input )>(
206 fract_first, fract_last, significant_digits );
209 if( exp_first and ( exp_last - exp_first ) > 0 ) {
210 signed_t
const exp_sign = [&] {
211 switch( *exp_first ) {
215 ErrorReason::InvalidNumber );
219 ErrorReason::InvalidNumber );
226 exponent += to_signed(
228 unsigned_t exp_result = 0;
229 if constexpr( ParseState::is_zero_terminated_string ) {
230 auto dig = parse_digit( *exp_first );
235 dig = parse_digit( *exp_first );
238 if( exp_first < exp_last ) {
239 auto dig = parse_digit( *exp_first );
247 if( exp_first >= exp_last ) {
250 dig = parse_digit( *exp_first );
258 if constexpr( std::is_floating_point_v<Result> and
259 ParseState::precise_ieee754 ) {
263 use_strtod |= exponent > 22;
264 use_strtod |= exponent < -22;
265 use_strtod |= significant_digits > 9007199254740992ULL;
266 if( std::is_same_v<Result, long double> or
267 DAW_UNLIKELY( use_strtod ) ) {
268 return json_details::parse_with_strtod<Result>( parse_state.first,
273 power10<Result>( ParseState::exec_tag,
274 static_cast<Result
>( significant_digits ),
278 template<
typename Result,
typename ParseState>
279 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
280 parse_real_unknown( ParseState &parse_state ) {
283 parse_state.has_more( ) and
284 parse_policy_details::is_number_start( parse_state.front( ) ),
285 ErrorReason::InvalidNumberStart,
288 daw::not_null<char const *>
const orig_first = parse_state.first;
289 daw::not_null<char const *>
const orig_last = parse_state.last;
296 auto const sign =
static_cast<Result
>(
297 parse_policy_details::validate_signed_first( parse_state ) );
299 using max_storage_digits = daw::constant<static_cast<std::int64_t>(
300 daw::digits10<std::uint64_t> )>;
301 using max_exponent = daw::constant<static_cast<std::int64_t>(
302 daw::max_digits10<Result> + 1 )>;
304 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
308 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
312 daw::not_null<char const *> first = parse_state.first;
313 daw::not_null<char const *>
const last = parse_state.last;
314 daw::not_null<char const *>
const whole_last =
316 (std::min)( parse_state.last - parse_state.first,
317 static_cast<std::ptrdiff_t
>( max_exponent::value ) );
319 unsigned_t significant_digits = 0;
320 daw::not_null<char const *> last_char =
321 parse_digits_while_number<( ParseState::is_zero_terminated_string or
322 ParseState::is_unchecked_input )>(
323 first.get( ), whole_last.get( ), significant_digits );
324 auto sig_digit_count = last_char - parse_state.first;
326 std::is_floating_point_v<Result> and ParseState::precise_ieee754 and
327 DAW_UNLIKELY( sig_digit_count > max_storage_digits::value );
328 signed_t exponent_p1 = [&] {
329 if( DAW_UNLIKELY( last_char >= whole_last ) ) {
330 if constexpr( std::is_floating_point_v<Result> and
331 ParseState::precise_ieee754 ) {
336 daw::not_null<char const *> ptr =
337 skip_digits<( ParseState::is_zero_terminated_string or
338 ParseState::is_unchecked_input )>( last_char,
340 auto const diff = ptr - last_char;
343 if( significant_digits == 0 ) {
344 return signed_t{ 0 };
346 return static_cast<signed_t
>( diff );
348 return signed_t{ 0 };
352 if( ( ParseState::is_zero_terminated_string or
353 ParseState::is_unchecked_input or
354 DAW_LIKELY( first < parse_state.last ) ) and
357 if( exponent_p1 != 0 ) {
358 if( first < parse_state.last ) {
360 skip_digits<( ParseState::is_zero_terminated_string or
361 ParseState::is_unchecked_input )>( first, last );
364 daw::not_null<char const *> fract_last =
365 first + (std::min)( parse_state.last - first,
366 static_cast<std::ptrdiff_t
>(
367 max_exponent::value -
368 ( first - parse_state.first ) ) );
370 last_char = parse_digits_while_number<(
371 ParseState::is_zero_terminated_string or
372 ParseState::is_unchecked_input )>(
373 first.get( ), fract_last.get( ), significant_digits );
374 sig_digit_count += last_char - first;
375 exponent_p1 -=
static_cast<signed_t
>( last_char - first );
377 if( daw::nsc_and( first >= fract_last, first < last ) ) {
379 skip_digits<( ParseState::is_zero_terminated_string or
380 ParseState::is_unchecked_input )>( first, last );
381 if constexpr( std::is_floating_point_v<Result> and
382 ParseState::precise_ieee754 ) {
383 use_strtod |= new_first > first;
390 signed_t
const exponent_p2 = [&] {
391 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
392 ( ( *first | 0x20 ) ==
'e' ) ) {
394 signed_t
const exp_sign = [&] {
396 first < parse_state.last ),
397 ErrorReason::UnexpectedEndOfData,
398 parse_state.copy( first ) );
403 ( parse_digit( *first ) < 10U ),
404 ErrorReason::InvalidNumber );
405 return signed_t{ 1 };
409 parse_digit( *first ) < 10U,
410 ErrorReason::InvalidNumber );
411 return signed_t{ -1 };
414 ErrorReason::InvalidNumber );
415 return signed_t{ 1 };
419 ErrorReason::UnexpectedEndOfData,
421 unsigned_t exp_tmp = 0;
422 using skip_end_check =
423 std::bool_constant<ParseState::is_zero_terminated_string or
424 ParseState::is_unchecked_input>;
425 last_char = parse_digits_while_number<skip_end_check::value>(
426 first.get( ), last.get( ), exp_tmp );
428 return to_signed( exp_tmp, exp_sign );
430 return signed_t{ 0 };
432 auto const exponent = [&] {
433 if constexpr( ParseState::is_unchecked_input or
434 not std::is_floating_point_v<Result> ) {
435 return exponent_p1 + exponent_p2;
437 if(
bool const matching_signs =
438 ( ( exponent_p1 < 0 ) == ( exponent_p2 < 0 ) );
439 not matching_signs ) {
441 return exponent_p1 + exponent_p2;
443 auto const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
445 if( DAW_UNLIKELY( ( daw::min_value<signed_t> - exponent_p1 ) >
449 return daw::min_value<signed_t>;
451 return exponent_p1 + exponent_p2;
453 auto const r =
static_cast<unsigned_t
>( exponent_p1 ) +
454 static_cast<unsigned_t
>( exponent_p2 );
456 r >
static_cast<unsigned_t
>( daw::max_value<signed_t> ) ) ) {
457 return daw::max_value<signed_t>;
459 return static_cast<signed_t
>( r );
462 parse_state.first = first;
464 if constexpr( std::is_floating_point_v<Result> and
465 ParseState::precise_ieee754 ) {
466 use_strtod |= DAW_UNLIKELY( exponent > 22 );
467 use_strtod |= DAW_UNLIKELY( exponent < -22 );
469 DAW_UNLIKELY( significant_digits > 9007199254740992ULL );
470 if( DAW_UNLIKELY( use_strtod ) ) {
471 using json_details::parse_with_strtod;
472 auto result = parse_with_strtod<Result>( orig_first, orig_last );
480 power10<Result>( ParseState::exec_tag,
481 static_cast<Result
>( significant_digits ),
485 template<
typename Result,
bool KnownRange,
typename ParseState>
486 [[nodiscard]]
constexpr Result parse_real( ParseState &parse_state ) {
487 if constexpr( KnownRange ) {
488 return parse_real_known<Result>( parse_state );
490 return parse_real_unknown<Result>( parse_state );