36 namespace json_details {
37 template<
bool skip_end_check,
typename Un
signed>
38 DAW_ATTRIB_FLATINLINE
constexpr void
39 parse_digits_until_last( daw::not_null<char const *> first,
40 daw::not_null<char const *>
const last,
41 Unsigned &DAW_RESTRICT v ) {
43 while( last - first >= 16 ) {
44 value *=
static_cast<Unsigned
>( 10'000'000'000'000'000ULL );
45 value +=
static_cast<Unsigned
>( parse_16_digits( first ) );
48 if( last - first >= 8 ) {
49 value *=
static_cast<Unsigned
>( 100'000'000U );
50 value +=
static_cast<Unsigned
>( parse_8_digits( first ) );
53 if constexpr( skip_end_check ) {
54 auto dig = parse_digit( *first );
59 dig = parse_digit( *first );
62 while( DAW_LIKELY( first < last ) ) {
64 value += parse_digit( *first );
71 template<
typename Un
signed>
72 constexpr std::size_t count_digits( Unsigned value ) {
73 if( DAW_LIKELY( value == 0 ) ) {
77 if constexpr(
sizeof( Unsigned ) <=
sizeof( std::uint64_t ) ) {
78 if( value >= 10000000000000000000ULL ) {
81 if( value >= 1000000000000000000ULL ) {
84 if( value >= 100000000000000000ULL ) {
87 if( value >= 10000000000000000ULL ) {
90 if( value >= 1000000000000000ULL ) {
93 if( value >= 100000000000000ULL ) {
96 if( value >= 10000000000000ULL ) {
99 if( value >= 1000000000000ULL ) {
102 if( value >= 100000000000ULL ) {
105 if( value >= 10000000000ULL ) {
108 if( value >= 1000000000ULL ) {
111 if( value >= 100000000ULL ) {
114 if( value >= 10000000ULL ) {
117 if( value >= 1000000ULL ) {
120 if( value >= 100000ULL ) {
123 if( value >= 10000ULL ) {
126 if( value >= 1000ULL ) {
129 if( value >= 100ULL ) {
132 if( value >= 10ULL ) {
137 std::size_t count = 1;
138 value /= Unsigned{ 10U };
141 value /= Unsigned{ 10U };
147 template<
typename iterator,
typename Un
signed>
148 [[nodiscard]] DAW_ATTRIB_FLATINLINE
constexpr daw::not_null<iterator>
149 parse_digits_while_number( daw::not_null<iterator> first,
150 daw::not_null<iterator>
const last,
151 Unsigned &DAW_RESTRICT v,
152 std::size_t sig_dig_in_use ) {
154 if( DAW_UNLIKELY( first >= last ) ) {
158 auto const last_pos =
159 (std::min)( { std::distance( first, last ),
160 static_cast<std::ptrdiff_t
>( daw::digits10<Unsigned> -
161 sig_dig_in_use ) } );
162 daw::not_null
const new_last = std::next( first.get( ), last_pos );
165 if( new_last - first >= 8 and
166 is_made_of_eight_digits_cx( first.get( ) ) ) {
167 value *=
static_cast<Unsigned
>( 100'000'000U );
168 value +=
static_cast<Unsigned
>( parse_8_digits( first.get( ) ) );
173 if( first < new_last ) {
175 dig = parse_digit( *first );
182 }
while( first < new_last );
184 while( first < last ) {
185 dig = parse_digit( *first );
197 template<
typename ParseState,
typename Result,
198 typename max_storage_digits>
199 [[nodiscard]]
constexpr bool should_use_fallback(
200 [[maybe_unused]] daw::not_null<char const *> whole_first,
201 [[maybe_unused]] daw::not_null<char const *>
const whole_last,
202 [[maybe_unused]]
char const *fract_first,
203 [[maybe_unused]]
char const *fract_last ) {
204 if constexpr( std::is_floating_point_v<Result> and
205 ParseState::precise_ieee754 ) {
207 ( ( whole_last - whole_first ) +
208 ( fract_first ? fract_last - fract_first : 0 ) ) >
209 max_storage_digits::value );
215 inline constexpr std::size_t eisellemire_max_digits = 19;
217 template<
typename Signed>
218 [[nodiscard]]
constexpr bool
219 append_discarded_digits(
char const *first,
char const *last,
220 std::uint64_t &significant_digits,
222 if( first ==
nullptr or first == last ) {
226 auto retained_digits = count_digits( significant_digits );
227 bool discarded_nonzero =
false;
228 while( first < last ) {
229 auto const digit = parse_digit( *first );
234 if( retained_digits < eisellemire_max_digits ) {
236 significant_digits * std::uint64_t{ 10 } + digit;
238 if( significant_digits != 0 ) {
241 if( exponent > daw::lowest_value<Signed> ) {
245 discarded_nonzero |= digit != 0;
248 return discarded_nonzero;
251 template<
typename Result,
typename Signed>
252 [[nodiscard]]
constexpr Result parse_truncated_lemire(
253 bool negative, Signed exponent, std::uint64_t significant_digits,
254 bool discarded_nonzero, daw::not_null<char const *> number_first,
255 daw::not_null<char const *> number_last ) {
256 auto const lower = json_details::parse_real_eisellemire<Result>(
257 negative, exponent, significant_digits );
258 if( not discarded_nonzero ) {
264 auto const upper = json_details::parse_real_eisellemire<Result>(
265 negative, exponent, significant_digits + std::uint64_t{ 1 } );
266 if( lower == upper ) {
270 return json_details::parse_json_real_exact<Result>(
271 negative, number_first, number_last );
274 template<
typename Result,
typename ParseState>
275 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
276 parse_real_known( ParseState &parse_state ) {
279 parse_state.has_more( ) and
280 parse_policy_details::is_number_start( parse_state.front( ) ),
281 ErrorReason::InvalidNumberStart,
284 daw::not_null<char const *> whole_first = parse_state.first;
285 char const *whole_last = parse_state.class_first
286 ? parse_state.class_first
287 : parse_state.class_last;
288 char const *fract_first =
289 parse_state.class_first ? parse_state.class_first + 1 :
nullptr;
290 char const *fract_last = parse_state.class_last;
291 char const *exp_first =
292 parse_state.class_last ? parse_state.class_last + 1 :
nullptr;
293 daw::not_null<char const *>
const exp_last = parse_state.last;
295 if( parse_state.class_first ==
nullptr ) {
296 if( parse_state.class_last ==
nullptr ) {
297 whole_last = parse_state.last;
299 whole_last = parse_state.class_last;
301 }
else if( parse_state.class_last ==
nullptr ) {
302 fract_last = parse_state.last;
304 char const *
const all_whole_last = whole_last;
305 char const *
const all_fract_first = fract_first;
306 char const *
const all_fract_last = fract_last;
308 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
309 daw::digits10<std::uint64_t> )>;
311 Result
const sign = [&] {
312 if( *whole_first ==
'-' ) {
314 return static_cast<Result
>( -1.0 );
316 return static_cast<Result
>( 1.0 );
320 should_use_fallback<ParseState, Result, max_storage_digits>(
321 whole_first, whole_last, fract_first, fract_last );
323 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
324 daw::max_digits10<Result> + 1 )>;
326 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
331 typename daw::conditional_t<std::is_floating_point_v<unsigned_t>,
332 daw::traits::identity<unsigned_t>,
333 std::make_signed<unsigned_t>>::type;
334 std::intmax_t whole_exponent_available = whole_last - whole_first;
335 std::intmax_t fract_exponent_available =
336 fract_first ? fract_last - fract_first : 0;
337 signed_t exponent = 0;
339 if( whole_exponent_available > max_exponent::value ) {
340 whole_last = whole_first + max_exponent::value;
341 whole_exponent_available -= max_exponent::value;
342 fract_exponent_available = 0;
343 fract_first =
nullptr;
344 exponent = whole_exponent_available;
346 whole_exponent_available =
347 max_exponent::value - whole_exponent_available;
348 if constexpr( ParseState::precise_ieee754 ) {
349 use_fallback |= DAW_UNLIKELY( fract_exponent_available >
350 whole_exponent_available );
352 if( whole_exponent_available < fract_exponent_available ) {
353 fract_exponent_available = whole_exponent_available;
355 exponent = -fract_exponent_available;
356 fract_last = fract_first + fract_exponent_available;
359 unsigned_t significant_digits = 0;
360 parse_digits_until_last<( ParseState::is_zero_terminated_string or
361 ParseState::is_unchecked_input )>(
362 whole_first, whole_last, significant_digits );
364 parse_digits_until_last<( ParseState::is_zero_terminated_string or
365 ParseState::is_unchecked_input )>(
366 fract_first, fract_last, significant_digits );
369 if( exp_first and ( exp_last - exp_first ) > 0 ) {
370 signed_t
const exp_sign = [&] {
371 switch( *exp_first ) {
375 parse_digit( *exp_first ) < 10U,
376 ErrorReason::InvalidNumber );
381 parse_digit( *exp_first ) < 10U,
382 ErrorReason::InvalidNumber );
386 ErrorReason::InvalidNumber );
390 exponent += to_signed(
392 unsigned_t exp_result = 0;
393 if constexpr( ParseState::is_zero_terminated_string ) {
394 auto dig = parse_digit( *exp_first );
399 dig = parse_digit( *exp_first );
402 if( exp_first < exp_last ) {
403 auto dig = parse_digit( *exp_first );
411 if( exp_first >= exp_last ) {
414 dig = parse_digit( *exp_first );
422 if constexpr( std::is_floating_point_v<Result> and
423 ParseState::precise_ieee754 ) {
430 DAW_CPP23_STATIC_LOCAL
constexpr bool is_lemire_capable =
431 std::is_same_v<Result, float> or std::is_same_v<Result, double> or
432 is_double_sized_long_double_v<Result>;
433 DAW_CPP23_STATIC_LOCAL
constexpr bool is_extended_long_double =
434 std::is_same_v<Result, long double> and not is_lemire_capable;
435 DAW_CPP23_STATIC_LOCAL
constexpr bool is_80bit_long_double_v =
436 std::is_same_v<Result, long double> and
437 std::numeric_limits<long double>::digits == 64;
439 DAW_CPP23_STATIC_LOCAL
constexpr bool is_128bit_long_double_v =
440 std::is_same_v<Result, long double> and
441 std::numeric_limits<long double>::digits == 113;
445 DAW_CPP23_STATIC_LOCAL
constexpr int pow10_threshold =
446 is_80bit_long_double_v ? 27
447 : is_128bit_long_double_v ? 48
449 use_fallback |= exponent > pow10_threshold;
450 use_fallback |= exponent < -pow10_threshold;
451 if constexpr( is_lemire_capable ) {
452 use_fallback |= significant_digits >
453 ( std::uint64_t{ 1 } << daw::digits<Result> );
455 if( DAW_UNLIKELY( use_fallback ) ) {
456 if constexpr( is_lemire_capable ) {
457 bool discarded_nonzero = append_discarded_digits(
458 whole_last, all_whole_last, significant_digits, exponent );
459 if( all_fract_first !=
nullptr ) {
460 auto const *discarded_fract_first =
461 fract_first ==
nullptr ? all_fract_first : fract_last;
463 append_discarded_digits( discarded_fract_first,
469 std::conditional_t<std::is_same_v<Result, long double>,
472 return static_cast<Result
>(
473 parse_truncated_lemire<compute_t>( sign < Result{ 0 },
478 parse_state.last ) );
480 static_assert( is_extended_long_double );
481 return json_details::parse_with_strtod<Result>(
482 parse_state.first, parse_state.last );
487 power10<Result>( ParseState::exec_tag,
488 static_cast<Result
>( significant_digits ),
492 template<
typename Result,
typename ParseState>
493 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
494 parse_real_unknown( ParseState &parse_state ) {
497 parse_state.has_more( ) and
498 parse_policy_details::is_number_start( parse_state.front( ) ),
499 ErrorReason::InvalidNumberStart,
502 using iterator_t =
typename ParseState::iterator;
503 [[maybe_unused]] daw::not_null<iterator_t>
const orig_first =
507 parse_policy_details::validate_signed_first( parse_state );
509 using max_storage_digits = daw::constant<static_cast<std::int64_t>(
510 daw::digits10<std::uint64_t> )>;
511 using max_exponent = daw::constant<static_cast<std::int64_t>(
512 daw::max_digits10<Result> + 1 )>;
514 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
518 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
522 daw::not_null<iterator_t> first = parse_state.first;
523 daw::not_null<iterator_t>
const last = parse_state.last;
524 daw::not_null<iterator_t>
const whole_last =
526 (std::min)( { parse_state.last - parse_state.first,
527 static_cast<std::ptrdiff_t
>( max_exponent::value ) } );
529 unsigned_t significant_digits = 0;
530 iterator_t discarded_whole_first =
nullptr;
531 iterator_t discarded_whole_last =
nullptr;
532 iterator_t discarded_fract_first =
nullptr;
533 iterator_t discarded_fract_last =
nullptr;
534 daw::not_null<iterator_t> last_char =
535 parse_digits_while_number<iterator_t>(
536 first.get( ), whole_last.get( ), significant_digits, 0 );
537 auto const parsed_whole_digit_count = last_char - parse_state.first;
538 auto const stored_whole_digit_count = [&] {
539 if( significant_digits == 0 ) {
540 return std::size_t{ 0 };
542 auto first_nonzero = parse_state.first;
543 while( *first_nonzero ==
'0' ) {
546 return static_cast<std::size_t
>( last_char - first_nonzero );
549 std::is_floating_point_v<Result> and ParseState::precise_ieee754 and
550 DAW_UNLIKELY( parsed_whole_digit_count > max_storage_digits::value );
551 signed_t exponent_p1 = [&] {
552 if( DAW_UNLIKELY( last_char >= whole_last ) ) {
553 if constexpr( std::is_floating_point_v<Result> and
554 ParseState::precise_ieee754 ) {
559 daw::not_null<iterator_t> ptr =
560 skip_digits<( ParseState::is_zero_terminated_string or
561 ParseState::is_unchecked_input )>( last_char,
563 discarded_whole_first = last_char.get( );
564 discarded_whole_last = ptr.get( );
565 auto const diff = ptr - last_char;
568 if( significant_digits == 0 ) {
569 return signed_t{ 0 };
571 return static_cast<signed_t
>( diff );
573 return signed_t{ 0 };
577 if( ( ParseState::is_zero_terminated_string or
578 ParseState::is_unchecked_input or
579 DAW_LIKELY( first < parse_state.last ) ) and
582 if( exponent_p1 != 0 ) {
583 if( first < parse_state.last ) {
584 auto const discarded_first = first;
586 skip_digits<( ParseState::is_zero_terminated_string or
587 ParseState::is_unchecked_input )>( first, last );
588 discarded_fract_first = discarded_first.get( );
589 discarded_fract_last = first.get( );
592 daw::not_null<iterator_t> fract_last =
593 first + (std::min)( parse_state.last - first,
594 static_cast<std::ptrdiff_t
>(
595 max_exponent::value -
596 ( first - parse_state.first ) ) );
599 parse_digits_while_number<iterator_t>( first.get( ),
602 stored_whole_digit_count );
606 auto const fract_stored_cap =
static_cast<std::ptrdiff_t
>(
607 daw::digits10<unsigned_t> - stored_whole_digit_count );
608 exponent_p1 -=
static_cast<signed_t
>(
609 (std::min)( { last_char - first, fract_stored_cap } ) );
610 if constexpr( std::is_floating_point_v<Result> and
611 ParseState::precise_ieee754 ) {
614 use_strtod |= ( last_char - first ) > fract_stored_cap;
617 if( daw::nsc_and( first >= fract_last, first < last ) ) {
619 skip_digits<( ParseState::is_zero_terminated_string or
620 ParseState::is_unchecked_input )>( first, last );
621 discarded_fract_first = first.get( );
622 discarded_fract_last = new_first.get( );
623 if constexpr( std::is_floating_point_v<Result> and
624 ParseState::precise_ieee754 ) {
625 use_strtod |= new_first > first;
632 signed_t
const exponent_p2 = [&] {
633 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
634 ( ( *first | 0x20 ) ==
'e' ) ) {
636 signed_t
const exp_sign = [&] {
638 first < parse_state.last ),
639 ErrorReason::UnexpectedEndOfData,
640 parse_state.copy( first ) );
645 ( parse_digit( *first ) < 10U ),
646 ErrorReason::InvalidNumber );
647 return signed_t{ 1 };
651 parse_digit( *first ) < 10U,
652 ErrorReason::InvalidNumber );
653 return signed_t{ -1 };
656 ErrorReason::InvalidNumber );
657 return signed_t{ 1 };
661 ErrorReason::UnexpectedEndOfData,
663 unsigned_t exp_tmp = 0;
664 last_char = parse_digits_while_number( first, last, exp_tmp, 0 );
666 return to_signed( exp_tmp, exp_sign );
668 return signed_t{ 0 };
670 auto exponent = [&] {
671 if constexpr( ParseState::is_unchecked_input or
672 not std::is_floating_point_v<Result> ) {
673 return exponent_p1 + exponent_p2;
675 if(
bool const matching_signs =
676 ( ( exponent_p1 < 0 ) == ( exponent_p2 < 0 ) );
677 not matching_signs ) {
679 return exponent_p1 + exponent_p2;
681 signed_t
const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
683 if( DAW_UNLIKELY( ( daw::lowest_value<signed_t> - exponent_p1 ) >
687 return daw::lowest_value<signed_t>;
689 return exponent_p1 + exponent_p2;
691 auto const r =
static_cast<unsigned_t
>( exponent_p1 ) +
692 static_cast<unsigned_t
>( exponent_p2 );
694 r >
static_cast<unsigned_t
>( daw::max_value<signed_t> ) ) ) {
695 return daw::max_value<signed_t>;
697 return static_cast<signed_t
>( r );
700 parse_state.first = first;
702 if constexpr( std::is_floating_point_v<Result> and
703 ParseState::precise_ieee754 ) {
707 DAW_CPP23_STATIC_LOCAL
constexpr bool is_lemire_capable =
708 std::is_same_v<Result, float> or std::is_same_v<Result, double> or
709 is_double_sized_long_double_v<Result>;
710 DAW_CPP23_STATIC_LOCAL
constexpr bool is_80bit_long_double_v =
711 std::is_same_v<Result, long double> and
712 std::numeric_limits<long double>::digits == 64;
713 DAW_CPP23_STATIC_LOCAL
constexpr bool is_128bit_long_double_v =
714 std::is_same_v<Result, long double> and
715 std::numeric_limits<long double>::digits == 113;
717 DAW_CPP23_STATIC_LOCAL
constexpr int pow10_threshold =
718 is_80bit_long_double_v ? 27
719 : is_128bit_long_double_v ? 48
721 use_strtod |= DAW_UNLIKELY( exponent > pow10_threshold );
722 use_strtod |= DAW_UNLIKELY( exponent < -pow10_threshold );
723 if constexpr( is_lemire_capable ) {
724 use_strtod |= DAW_UNLIKELY(
725 significant_digits > (std::uint64_t{ 1 } << daw::digits<Result>));
727 if( DAW_UNLIKELY( use_strtod ) ) {
728 if constexpr( is_lemire_capable ) {
729 bool discarded_nonzero =
730 append_discarded_digits( discarded_whole_first,
731 discarded_whole_last,
735 append_discarded_digits( discarded_fract_first,
736 discarded_fract_last,
740 std::conditional_t<std::is_same_v<Result, long double>,
743 return static_cast<Result
>(
744 parse_truncated_lemire<compute_t>( sign < 0,
751 static_assert( std::is_same_v<Result, long double> );
752 return json_details::parse_with_strtod<Result>( orig_first.get( ),
757 return static_cast<Result
>( sign ) *
758 power10<Result>( ParseState::exec_tag,
759 static_cast<Result
>( significant_digits ),
763 template<
typename Result,
bool KnownRange,
typename ParseState>
764 [[nodiscard]]
constexpr Result parse_real( ParseState &parse_state ) {
765 if constexpr( KnownRange ) {
766 return parse_real_known<Result>( parse_state );
768 return parse_real_unknown<Result>( parse_state );