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 if constexpr( skip_end_check ) {
44 auto dig = parse_digit( *first );
49 dig = parse_digit( *first );
52 while( DAW_LIKELY( first < last ) ) {
54 value += parse_digit( *first );
61 template<
typename Un
signed>
62 constexpr std::size_t count_digits( Unsigned value ) {
63 if( DAW_LIKELY( value == 0 ) ) {
67 if constexpr(
sizeof( Unsigned ) <=
sizeof( std::uint64_t ) ) {
68 if( value >= 10000000000000000000ULL ) {
71 if( value >= 1000000000000000000ULL ) {
74 if( value >= 100000000000000000ULL ) {
77 if( value >= 10000000000000000ULL ) {
80 if( value >= 1000000000000000ULL ) {
83 if( value >= 100000000000000ULL ) {
86 if( value >= 10000000000000ULL ) {
89 if( value >= 1000000000000ULL ) {
92 if( value >= 100000000000ULL ) {
95 if( value >= 10000000000ULL ) {
98 if( value >= 1000000000ULL ) {
101 if( value >= 100000000ULL ) {
104 if( value >= 10000000ULL ) {
107 if( value >= 1000000ULL ) {
110 if( value >= 100000ULL ) {
113 if( value >= 10000ULL ) {
116 if( value >= 1000ULL ) {
119 if( value >= 100ULL ) {
122 if( value >= 10ULL ) {
127 std::size_t count = 1;
128 value /= Unsigned{ 10U };
131 value /= Unsigned{ 10U };
137 template<
typename Un
signed>
138 [[nodiscard]] DAW_ATTRIB_FLATINLINE
constexpr daw::not_null<char const *>
139 parse_digits_while_number( daw::not_null<char const *> first,
140 daw::not_null<char const *>
const last,
141 Unsigned &DAW_RESTRICT v ) {
143 if( DAW_UNLIKELY( first >= last ) ) {
147 auto const sig_dig_in_use = count_digits( v );
149 auto const last_pos =
150 (std::min)( { std::distance( first, last ),
151 static_cast<std::ptrdiff_t
>( daw::digits10<Unsigned> -
152 sig_dig_in_use ) } );
153 daw::not_null
const new_last = std::next( first.get( ), last_pos );
159 dig = parse_digit( *first );
166 }
while( first < new_last );
167 if( first < last and dig < 10U ) {
170 while( first < last ) {
171 dig = parse_digit( *first );
183 template<
typename ParseState,
typename Result,
184 typename max_storage_digits>
185 [[nodiscard]]
constexpr bool should_use_fallback(
186 [[maybe_unused]] daw::not_null<char const *> whole_first,
187 [[maybe_unused]] daw::not_null<char const *>
const whole_last,
188 [[maybe_unused]]
char const *fract_first,
189 [[maybe_unused]]
char const *fract_last ) {
190 if constexpr( std::is_floating_point_v<Result> and
191 ParseState::precise_ieee754 ) {
193 ( ( whole_last - whole_first ) +
194 ( fract_first ? fract_last - fract_first : 0 ) ) >
195 max_storage_digits::value );
201 inline constexpr std::size_t eisellemire_max_digits = 19;
203 template<
typename Signed>
204 [[nodiscard]]
constexpr bool
205 append_discarded_digits(
char const *first,
char const *last,
206 std::uint64_t &significant_digits,
208 if( first ==
nullptr ) {
212 auto retained_digits = count_digits( significant_digits );
213 bool discarded_nonzero =
false;
214 while( first < last ) {
215 auto const digit = parse_digit( *first );
220 if( retained_digits < eisellemire_max_digits ) {
222 significant_digits * std::uint64_t{ 10 } + digit;
224 if( significant_digits != 0 ) {
227 if( exponent > std::numeric_limits<Signed>::lowest( ) ) {
231 discarded_nonzero |= digit != 0;
234 return discarded_nonzero;
237 template<
typename Result,
typename Signed>
238 [[nodiscard]]
constexpr Result parse_truncated_lemire(
239 bool negative, Signed exponent, std::uint64_t significant_digits,
240 bool discarded_nonzero, daw::not_null<char const *> number_first,
241 daw::not_null<char const *> number_last ) {
242 auto const lower = json_details::parse_real_eisellemire<Result>(
243 negative, exponent, significant_digits );
244 if( not discarded_nonzero ) {
250 auto const upper = json_details::parse_real_eisellemire<Result>(
251 negative, exponent, significant_digits + std::uint64_t{ 1 } );
252 if( lower == upper ) {
256 return json_details::parse_json_real_exact<Result>(
257 negative, number_first, number_last );
260 template<
typename Result,
typename ParseState>
261 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
262 parse_real_known( ParseState &parse_state ) {
265 parse_state.has_more( ) and
266 parse_policy_details::is_number_start( parse_state.front( ) ),
267 ErrorReason::InvalidNumberStart,
270 daw::not_null<char const *> whole_first = parse_state.first;
271 char const *whole_last = parse_state.class_first
272 ? parse_state.class_first
273 : parse_state.class_last;
274 char const *fract_first =
275 parse_state.class_first ? parse_state.class_first + 1 :
nullptr;
276 char const *fract_last = parse_state.class_last;
277 char const *exp_first =
278 parse_state.class_last ? parse_state.class_last + 1 :
nullptr;
279 daw::not_null<char const *>
const exp_last = parse_state.last;
281 if( parse_state.class_first ==
nullptr ) {
282 if( parse_state.class_last ==
nullptr ) {
283 whole_last = parse_state.last;
285 whole_last = parse_state.class_last;
287 }
else if( parse_state.class_last ==
nullptr ) {
288 fract_last = parse_state.last;
290 char const *
const all_whole_last = whole_last;
291 char const *
const all_fract_first = fract_first;
292 char const *
const all_fract_last = fract_last;
294 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
295 daw::digits10<std::uint64_t> )>;
297 Result
const sign = [&] {
298 if( *whole_first ==
'-' ) {
300 return static_cast<Result
>( -1.0 );
302 return static_cast<Result
>( 1.0 );
306 should_use_fallback<ParseState, Result, max_storage_digits>(
307 whole_first, whole_last, fract_first, fract_last );
309 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
310 daw::max_digits10<Result> + 1 )>;
312 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
317 typename daw::conditional_t<std::is_floating_point_v<unsigned_t>,
318 daw::traits::identity<unsigned_t>,
319 std::make_signed<unsigned_t>>::type;
320 std::intmax_t whole_exponent_available = whole_last - whole_first;
321 std::intmax_t fract_exponent_available =
322 fract_first ? fract_last - fract_first : 0;
323 signed_t exponent = 0;
325 if( whole_exponent_available > max_exponent::value ) {
326 whole_last = whole_first + max_exponent::value;
327 whole_exponent_available -= max_exponent::value;
328 fract_exponent_available = 0;
329 fract_first =
nullptr;
330 exponent = whole_exponent_available;
332 whole_exponent_available =
333 max_exponent::value - whole_exponent_available;
334 if constexpr( ParseState::precise_ieee754 ) {
335 use_fallback |= DAW_UNLIKELY( fract_exponent_available >
336 whole_exponent_available );
338 if( whole_exponent_available < fract_exponent_available ) {
339 fract_exponent_available = whole_exponent_available;
341 exponent = -fract_exponent_available;
342 fract_last = fract_first + fract_exponent_available;
345 unsigned_t significant_digits = 0;
346 parse_digits_until_last<( ParseState::is_zero_terminated_string or
347 ParseState::is_unchecked_input )>(
348 whole_first, whole_last, significant_digits );
350 parse_digits_until_last<( ParseState::is_zero_terminated_string or
351 ParseState::is_unchecked_input )>(
352 fract_first, fract_last, significant_digits );
355 if( exp_first and ( exp_last - exp_first ) > 0 ) {
356 signed_t
const exp_sign = [&] {
357 switch( *exp_first ) {
361 exp_first < exp_last and parse_digit( *exp_first ) < 10U,
362 ErrorReason::InvalidNumber );
367 exp_first < exp_last and parse_digit( *exp_first ) < 10U,
368 ErrorReason::InvalidNumber );
372 ErrorReason::InvalidNumber );
376 exponent += to_signed(
378 unsigned_t exp_result = 0;
379 if constexpr( ParseState::is_zero_terminated_string ) {
380 auto dig = parse_digit( *exp_first );
385 dig = parse_digit( *exp_first );
388 if( exp_first < exp_last ) {
389 auto dig = parse_digit( *exp_first );
397 if( exp_first >= exp_last ) {
400 dig = parse_digit( *exp_first );
408 if constexpr( std::is_floating_point_v<Result> and
409 ParseState::precise_ieee754 ) {
413 use_fallback |= exponent > 22;
414 use_fallback |= exponent < -22;
415 if constexpr( std::is_same_v<Result, float> or
416 std::is_same_v<Result, double> ) {
419 ( std::uint64_t{ 1 } << std::numeric_limits<Result>::digits );
421 if( std::is_same_v<Result, long double> or
422 DAW_UNLIKELY( use_fallback ) ) {
423 if constexpr( std::is_same_v<Result, float> or
424 std::is_same_v<Result, double> ) {
425 bool discarded_nonzero = append_discarded_digits(
426 whole_last, all_whole_last, significant_digits, exponent );
427 if( all_fract_first !=
nullptr ) {
428 auto const *discarded_fract_first =
429 fract_first ==
nullptr ? all_fract_first : fract_last;
431 append_discarded_digits( discarded_fract_first,
436 return parse_truncated_lemire<Result>( sign < Result{ 0 },
443 static_assert( std::is_same_v<Result, long double> );
444 return json_details::parse_with_strtod<Result>(
445 parse_state.first, parse_state.last );
450 power10<Result>( ParseState::exec_tag,
451 static_cast<Result
>( significant_digits ),
455 template<
typename Result,
typename ParseState>
456 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
457 parse_real_unknown( ParseState &parse_state ) {
460 parse_state.has_more( ) and
461 parse_policy_details::is_number_start( parse_state.front( ) ),
462 ErrorReason::InvalidNumberStart,
465 [[maybe_unused]] daw::not_null<char const *>
const orig_first =
468 auto const sign =
static_cast<Result
>(
469 parse_policy_details::validate_signed_first( parse_state ) );
471 using max_storage_digits = daw::constant<static_cast<std::int64_t>(
472 daw::digits10<std::uint64_t> )>;
473 using max_exponent = daw::constant<static_cast<std::int64_t>(
474 daw::max_digits10<Result> + 1 )>;
476 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
480 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
484 daw::not_null<char const *> first = parse_state.first;
485 daw::not_null<char const *>
const last = parse_state.last;
486 daw::not_null<char const *>
const whole_last =
488 (std::min)( { parse_state.last - parse_state.first,
489 static_cast<std::ptrdiff_t
>( max_exponent::value ) } );
491 unsigned_t significant_digits = 0;
492 char const *discarded_whole_first =
nullptr;
493 char const *discarded_whole_last =
nullptr;
494 char const *discarded_fract_first =
nullptr;
495 char const *discarded_fract_last =
nullptr;
496 daw::not_null<char const *> last_char = parse_digits_while_number(
497 first.get( ), whole_last.get( ), significant_digits );
498 auto const sig_digit_count = last_char - parse_state.first;
500 std::is_floating_point_v<Result> and ParseState::precise_ieee754 and
501 DAW_UNLIKELY( sig_digit_count > max_storage_digits::value );
502 signed_t exponent_p1 = [&] {
503 if( DAW_UNLIKELY( last_char >= whole_last ) ) {
504 if constexpr( std::is_floating_point_v<Result> and
505 ParseState::precise_ieee754 ) {
510 daw::not_null<char const *> ptr =
511 skip_digits<( ParseState::is_zero_terminated_string or
512 ParseState::is_unchecked_input )>( last_char,
514 discarded_whole_first = last_char.get( );
515 discarded_whole_last = ptr.get( );
516 auto const diff = ptr - last_char;
519 if( significant_digits == 0 ) {
520 return signed_t{ 0 };
522 return static_cast<signed_t
>( diff );
524 return signed_t{ 0 };
528 if( ( ParseState::is_zero_terminated_string or
529 ParseState::is_unchecked_input or
530 DAW_LIKELY( first < parse_state.last ) ) and
533 if( exponent_p1 != 0 ) {
534 if( first < parse_state.last ) {
535 auto const discarded_first = first;
537 skip_digits<( ParseState::is_zero_terminated_string or
538 ParseState::is_unchecked_input )>( first, last );
539 discarded_fract_first = discarded_first.get( );
540 discarded_fract_last = first.get( );
543 daw::not_null<char const *> fract_last =
544 first + (std::min)( parse_state.last - first,
545 static_cast<std::ptrdiff_t
>(
546 max_exponent::value -
547 ( first - parse_state.first ) ) );
549 last_char = parse_digits_while_number(
550 first.get( ), fract_last.get( ), significant_digits );
551 exponent_p1 -=
static_cast<signed_t
>( last_char - first );
553 if( daw::nsc_and( first >= fract_last, first < last ) ) {
555 skip_digits<( ParseState::is_zero_terminated_string or
556 ParseState::is_unchecked_input )>( first, last );
557 discarded_fract_first = first.get( );
558 discarded_fract_last = new_first.get( );
559 if constexpr( std::is_floating_point_v<Result> and
560 ParseState::precise_ieee754 ) {
561 use_strtod |= new_first > first;
568 signed_t
const exponent_p2 = [&] {
569 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
570 ( ( *first | 0x20 ) ==
'e' ) ) {
572 signed_t
const exp_sign = [&] {
574 first < parse_state.last ),
575 ErrorReason::UnexpectedEndOfData,
576 parse_state.copy( first ) );
581 ( parse_digit( *first ) < 10U ),
582 ErrorReason::InvalidNumber );
583 return signed_t{ 1 };
587 parse_digit( *first ) < 10U,
588 ErrorReason::InvalidNumber );
589 return signed_t{ -1 };
592 ErrorReason::InvalidNumber );
593 return signed_t{ 1 };
597 ErrorReason::UnexpectedEndOfData,
599 unsigned_t exp_tmp = 0;
601 parse_digits_while_number( first.get( ), last.get( ), exp_tmp );
603 return to_signed( exp_tmp, exp_sign );
605 return signed_t{ 0 };
607 auto exponent = [&] {
608 if constexpr( ParseState::is_unchecked_input or
609 not std::is_floating_point_v<Result> ) {
610 return exponent_p1 + exponent_p2;
612 if(
bool const matching_signs =
613 ( ( exponent_p1 < 0 ) == ( exponent_p2 < 0 ) );
614 not matching_signs ) {
616 return exponent_p1 + exponent_p2;
618 auto const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
620 if( DAW_UNLIKELY( ( daw::min_value<signed_t> - exponent_p1 ) >
624 return daw::min_value<signed_t>;
626 return exponent_p1 + exponent_p2;
628 auto const r =
static_cast<unsigned_t
>( exponent_p1 ) +
629 static_cast<unsigned_t
>( exponent_p2 );
631 r >
static_cast<unsigned_t
>( daw::max_value<signed_t> ) ) ) {
632 return daw::max_value<signed_t>;
634 return static_cast<signed_t
>( r );
637 parse_state.first = first;
639 if constexpr( std::is_floating_point_v<Result> and
640 ParseState::precise_ieee754 ) {
641 use_strtod |= DAW_UNLIKELY( exponent > 22 );
642 use_strtod |= DAW_UNLIKELY( exponent < -22 );
643 if constexpr( std::is_same_v<Result, float> or
644 std::is_same_v<Result, double> ) {
645 use_strtod |= DAW_UNLIKELY(
647 ( std::uint64_t{ 1 } << std::numeric_limits<Result>::digits ) );
649 if( DAW_UNLIKELY( use_strtod ) ) {
650 if constexpr( std::is_same_v<Result, float> or
651 std::is_same_v<Result, double> ) {
652 bool discarded_nonzero =
653 append_discarded_digits( discarded_whole_first,
654 discarded_whole_last,
658 append_discarded_digits( discarded_fract_first,
659 discarded_fract_last,
662 return parse_truncated_lemire<Result>( sign < Result{ 0 },
669 static_assert( std::is_same_v<Result, long double> );
670 return json_details::parse_with_strtod<Result>( orig_first,
676 power10<Result>( ParseState::exec_tag,
677 static_cast<Result
>( significant_digits ),
681 template<
typename Result,
bool KnownRange,
typename ParseState>
682 [[nodiscard]]
constexpr Result parse_real( ParseState &parse_state ) {
683 if constexpr( KnownRange ) {
684 return parse_real_known<Result>( parse_state );
686 return parse_real_unknown<Result>( parse_state );