DAW JSON Link
Loading...
Searching...
No Matches
daw_json_parse_real.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
12
22
23#include <daw/daw_cxmath.h>
24#include <daw/daw_likely.h>
25#include <daw/daw_not_null.h>
26#include <daw/daw_restrict.h>
27#include <daw/daw_utility.h>
28
29#include <cstddef>
30#include <cstdint>
31#include <limits>
32#include <type_traits>
33
34namespace daw::json {
35 inline namespace DAW_JSON_VER {
36 namespace json_details {
37 template<bool skip_end_check, typename Unsigned>
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 ) {
42 auto value = 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 ) );
46 first += 16;
47 }
48 if( last - first >= 8 ) {
49 value *= static_cast<Unsigned>( 100'000'000U );
50 value += static_cast<Unsigned>( parse_8_digits( first ) );
51 first += 8;
52 }
53 if constexpr( skip_end_check ) {
54 auto dig = parse_digit( *first );
55 while( dig < 10U ) {
56 value *= 10U;
57 value += dig;
58 ++first;
59 dig = parse_digit( *first );
60 }
61 } else {
62 while( DAW_LIKELY( first < last ) ) {
63 value *= 10U;
64 value += parse_digit( *first );
65 ++first;
66 }
67 }
68 v = value;
69 }
70
71 template<typename Unsigned>
72 constexpr std::size_t count_digits( Unsigned value ) {
73 if( DAW_LIKELY( value == 0 ) ) {
74 DAW_LIKELY_BRANCH
75 return 0;
76 }
77 if constexpr( sizeof( Unsigned ) <= sizeof( std::uint64_t ) ) {
78 if( value >= 10000000000000000000ULL ) {
79 return 20;
80 }
81 if( value >= 1000000000000000000ULL ) {
82 return 19;
83 }
84 if( value >= 100000000000000000ULL ) {
85 return 18;
86 }
87 if( value >= 10000000000000000ULL ) {
88 return 17;
89 }
90 if( value >= 1000000000000000ULL ) {
91 return 16;
92 }
93 if( value >= 100000000000000ULL ) {
94 return 15;
95 }
96 if( value >= 10000000000000ULL ) {
97 return 14;
98 }
99 if( value >= 1000000000000ULL ) {
100 return 13;
101 }
102 if( value >= 100000000000ULL ) {
103 return 12;
104 }
105 if( value >= 10000000000ULL ) {
106 return 11;
107 }
108 if( value >= 1000000000ULL ) {
109 return 10;
110 }
111 if( value >= 100000000ULL ) {
112 return 9;
113 }
114 if( value >= 10000000ULL ) {
115 return 8;
116 }
117 if( value >= 1000000ULL ) {
118 return 7;
119 }
120 if( value >= 100000ULL ) {
121 return 6;
122 }
123 if( value >= 10000ULL ) {
124 return 5;
125 }
126 if( value >= 1000ULL ) {
127 return 4;
128 }
129 if( value >= 100ULL ) {
130 return 3;
131 }
132 if( value >= 10ULL ) {
133 return 2;
134 }
135 return 1;
136 } else {
137 std::size_t count = 1;
138 value /= Unsigned{ 10U };
139 while( value > 0 ) {
140 ++count;
141 value /= Unsigned{ 10U };
142 }
143 return count;
144 }
145 }
146
147 template<typename iterator, typename Unsigned>
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 ) {
153
154 if( DAW_UNLIKELY( first >= last ) ) {
155 DAW_UNLIKELY_BRANCH
156 return first;
157 }
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 );
163
164 auto value = v;
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( ) ) );
169 first += 8;
170 }
171
172 unsigned dig = 10U;
173 if( first < new_last ) {
174 do {
175 dig = parse_digit( *first );
176 if( dig >= 10U ) {
177 break;
178 }
179 value *= 10U;
180 value += dig;
181 ++first;
182 } while( first < new_last );
183 }
184 while( first < last ) {
185 dig = parse_digit( *first );
186 if( dig >= 10U ) {
187 break;
188 }
189 ++first;
190 }
191 v = value;
192 return first;
193 }
194
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 ) {
206 return DAW_UNLIKELY(
207 ( ( whole_last - whole_first ) +
208 ( fract_first ? fract_last - fract_first : 0 ) ) >
209 max_storage_digits::value );
210 } else {
211 return false;
212 }
213 }
214
215 inline constexpr std::size_t eisellemire_max_digits = 19;
216
217 template<typename Signed>
218 [[nodiscard]] constexpr bool
219 append_discarded_digits( char const *first, char const *last,
220 std::uint64_t &significant_digits,
221 Signed &exponent ) {
222 if( first == nullptr or first == last ) {
223 return false;
224 }
225
226 auto retained_digits = count_digits( significant_digits );
227 bool discarded_nonzero = false;
228 while( first < last ) {
229 auto const digit = parse_digit( *first );
230 if( digit >= 10U ) {
231 break;
232 }
233 ++first;
234 if( retained_digits < eisellemire_max_digits ) {
235 significant_digits =
236 significant_digits * std::uint64_t{ 10 } + digit;
237 // Leading zeroes do not consume significant-digit capacity.
238 if( significant_digits != 0 ) {
239 ++retained_digits;
240 }
241 if( exponent > daw::lowest_value<Signed> ) {
242 --exponent;
243 }
244 } else {
245 discarded_nonzero |= digit != 0;
246 }
247 }
248 return discarded_nonzero;
249 }
250
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 ) {
259 return lower;
260 }
261
262 // significant_digits contains at most 19 decimal digits, so adding
263 // one cannot overflow a uint64_t.
264 auto const upper = json_details::parse_real_eisellemire<Result>(
265 negative, exponent, significant_digits + std::uint64_t{ 1 } );
266 if( lower == upper ) {
267 return lower;
268 }
269
270 return json_details::parse_json_real_exact<Result>(
271 negative, number_first, number_last );
272 }
273
274 template<typename Result, typename ParseState>
275 [[nodiscard]] DAW_ATTRIB_INLINE static constexpr Result
276 parse_real_known( ParseState &parse_state ) {
277 // [-]WHOLE[.FRACTION][(e|E)[+|-]EXPONENT]
279 parse_state.has_more( ) and
280 parse_policy_details::is_number_start( parse_state.front( ) ),
281 ErrorReason::InvalidNumberStart,
282 parse_state );
283
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;
294
295 if( parse_state.class_first == nullptr ) {
296 if( parse_state.class_last == nullptr ) {
297 whole_last = parse_state.last;
298 } else {
299 whole_last = parse_state.class_last;
300 }
301 } else if( parse_state.class_last == nullptr ) {
302 fract_last = parse_state.last;
303 }
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;
307
308 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
309 daw::digits10<std::uint64_t> )>;
310
311 Result const sign = [&] {
312 if( *whole_first == '-' ) {
313 ++whole_first;
314 return static_cast<Result>( -1.0 );
315 }
316 return static_cast<Result>( 1.0 );
317 }( );
318
319 bool use_fallback =
320 should_use_fallback<ParseState, Result, max_storage_digits>(
321 whole_first, whole_last, fract_first, fract_last );
322
323 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
324 daw::max_digits10<Result> + 1 )>;
325 using unsigned_t =
326 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
327 std::uint64_t,
328 Result>;
329
330 using signed_t =
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;
338
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;
345 } else {
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 );
351 }
352 if( whole_exponent_available < fract_exponent_available ) {
353 fract_exponent_available = whole_exponent_available;
354 }
355 exponent = -fract_exponent_available;
356 fract_last = fract_first + fract_exponent_available;
357 }
358
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 );
363 if( fract_first ) {
364 parse_digits_until_last<( ParseState::is_zero_terminated_string or
365 ParseState::is_unchecked_input )>(
366 fract_first, fract_last, significant_digits );
367 }
368
369 if( exp_first and ( exp_last - exp_first ) > 0 ) {
370 signed_t const exp_sign = [&] {
371 switch( *exp_first ) {
372 case '-':
373 ++exp_first;
374 daw_json_assert_weak( exp_first < exp_last and
375 parse_digit( *exp_first ) < 10U,
376 ErrorReason::InvalidNumber );
377 return -1;
378 case '+':
379 ++exp_first;
380 daw_json_assert_weak( exp_first < exp_last and
381 parse_digit( *exp_first ) < 10U,
382 ErrorReason::InvalidNumber );
383 return 1;
384 default:
385 daw_json_assert_weak( parse_digit( *exp_first ) < 10U,
386 ErrorReason::InvalidNumber );
387 return 1;
388 }
389 }( );
390 exponent += to_signed(
391 [&] {
392 unsigned_t exp_result = 0;
393 if constexpr( ParseState::is_zero_terminated_string ) {
394 auto dig = parse_digit( *exp_first );
395 while( dig < 10U ) {
396 ++exp_first;
397 exp_result *= 10U;
398 exp_result += dig;
399 dig = parse_digit( *exp_first );
400 }
401 } else {
402 if( exp_first < exp_last ) {
403 auto dig = parse_digit( *exp_first );
404 do {
405 if( dig >= 10U ) {
406 break;
407 }
408 ++exp_first;
409 exp_result *= 10U;
410 exp_result += dig;
411 if( exp_first >= exp_last ) {
412 break;
413 }
414 dig = parse_digit( *exp_first );
415 } while( true );
416 }
417 }
418 return exp_result;
419 }( ),
420 exp_sign );
421 }
422 if constexpr( std::is_floating_point_v<Result> and
423 ParseState::precise_ieee754 ) {
424 // On std floating point types, check for conditions that cannot be
425 // precisely calculated using the normal method and use the fallback
426 // method(usually strtod/from_chars). long double that shares
427 // double's size/precision/exponent range (e.g. MSVC) is computed
428 // as double instead, since Eisel-Lemire only supports
429 // binary32/binary64.
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;
438
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;
442
443 // Extended long double (80-bit) can exactly represent 10^k for
444 // |k| <= 27 (5^27 < 2^64); Eisel-Lemire types are limited to 22.
445 DAW_CPP23_STATIC_LOCAL constexpr int pow10_threshold =
446 is_80bit_long_double_v ? 27
447 : is_128bit_long_double_v ? 48
448 : 22;
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> );
454 }
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;
462 discarded_nonzero |=
463 append_discarded_digits( discarded_fract_first,
464 all_fract_last,
465 significant_digits,
466 exponent );
467 }
468 using compute_t =
469 std::conditional_t<std::is_same_v<Result, long double>,
470 double,
471 Result>;
472 return static_cast<Result>(
473 parse_truncated_lemire<compute_t>( sign < Result{ 0 },
474 exponent,
475 significant_digits,
476 discarded_nonzero,
477 parse_state.first,
478 parse_state.last ) );
479 } else {
480 static_assert( is_extended_long_double );
481 return json_details::parse_with_strtod<Result>(
482 parse_state.first, parse_state.last );
483 }
484 }
485 }
486 return sign *
487 power10<Result>( ParseState::exec_tag,
488 static_cast<Result>( significant_digits ),
489 exponent );
490 }
491
492 template<typename Result, typename ParseState>
493 [[nodiscard]] DAW_ATTRIB_INLINE static constexpr Result
494 parse_real_unknown( ParseState &parse_state ) {
495 // [-]WHOLE[.FRACTION][(e|E)[+|-]EXPONENT]
497 parse_state.has_more( ) and
498 parse_policy_details::is_number_start( parse_state.front( ) ),
499 ErrorReason::InvalidNumberStart,
500 parse_state );
501
502 using iterator_t = typename ParseState::iterator;
503 [[maybe_unused]] daw::not_null<iterator_t> const orig_first =
504 parse_state.first;
505
506 auto const sign =
507 parse_policy_details::validate_signed_first( parse_state );
508
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 )>;
513 using unsigned_t =
514 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
515 std::uint64_t,
516 Result>;
517 using signed_t =
518 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
519 std::int64_t,
520 Result>;
521
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 =
525 parse_state.first +
526 (std::min)( { parse_state.last - parse_state.first,
527 static_cast<std::ptrdiff_t>( max_exponent::value ) } );
528
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 };
541 }
542 auto first_nonzero = parse_state.first;
543 while( *first_nonzero == '0' ) {
544 ++first_nonzero;
545 }
546 return static_cast<std::size_t>( last_char - first_nonzero );
547 }( );
548 bool use_strtod =
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 ) {
555 use_strtod = true;
556 }
557 // We have sig digits we cannot parse because there isn't enough
558 // room in a std::uint64_t
559 daw::not_null<iterator_t> ptr =
560 skip_digits<( ParseState::is_zero_terminated_string or
561 ParseState::is_unchecked_input )>( last_char,
562 last );
563 discarded_whole_first = last_char.get( );
564 discarded_whole_last = ptr.get( );
565 auto const diff = ptr - last_char;
566
567 last_char = ptr;
568 if( significant_digits == 0 ) {
569 return signed_t{ 0 };
570 }
571 return static_cast<signed_t>( diff );
572 }
573 return signed_t{ 0 };
574 }( );
575
576 first = last_char;
577 if( ( ParseState::is_zero_terminated_string or
578 ParseState::is_unchecked_input or
579 DAW_LIKELY( first < parse_state.last ) ) and
580 *first == '.' ) {
581 ++first;
582 if( exponent_p1 != 0 ) {
583 if( first < parse_state.last ) {
584 auto const discarded_first = first;
585 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( );
590 }
591 } else {
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 ) ) );
597
598 last_char =
599 parse_digits_while_number<iterator_t>( first.get( ),
600 fract_last.get( ),
601 significant_digits,
602 stored_whole_digit_count );
603 // Only count the digits actually stored in significant_digits;
604 // parse_digits_while_number skips overflow digits up to last_char
605 // but those must not adjust the decimal-point exponent.
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 ) {
612 // If we silently dropped fractional digits, the power10 result
613 // may be incorrectly rounded — fall back to strtod.
614 use_strtod |= ( last_char - first ) > fract_stored_cap;
615 }
616 first = last_char;
617 if( daw::nsc_and( first >= fract_last, first < last ) ) {
618 auto new_first =
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;
626 }
627 first = new_first;
628 }
629 }
630 }
631
632 signed_t const exponent_p2 = [&] {
633 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
634 ( ( *first | 0x20 ) == 'e' ) ) {
635 ++first;
636 signed_t const exp_sign = [&] {
637 daw_json_assert_weak( ( ParseState::is_zero_terminated_string or
638 first < parse_state.last ),
639 ErrorReason::UnexpectedEndOfData,
640 parse_state.copy( first ) );
641 switch( *first ) {
642 case '+':
643 ++first;
644 daw_json_assert_weak( ( first < parse_state.last ) and
645 ( parse_digit( *first ) < 10U ),
646 ErrorReason::InvalidNumber );
647 return signed_t{ 1 };
648 case '-':
649 ++first;
650 daw_json_assert_weak( first < parse_state.last and
651 parse_digit( *first ) < 10U,
652 ErrorReason::InvalidNumber );
653 return signed_t{ -1 };
654 default:
655 daw_json_assert_weak( parse_policy_details::is_number( *first ),
656 ErrorReason::InvalidNumber );
657 return signed_t{ 1 };
658 }
659 }( );
660 daw_json_assert_weak( first < parse_state.last,
661 ErrorReason::UnexpectedEndOfData,
662 parse_state );
663 unsigned_t exp_tmp = 0;
664 last_char = parse_digits_while_number( first, last, exp_tmp, 0 );
665 first = last_char;
666 return to_signed( exp_tmp, exp_sign );
667 }
668 return signed_t{ 0 };
669 }( );
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;
674 } else {
675 if( bool const matching_signs =
676 ( ( exponent_p1 < 0 ) == ( exponent_p2 < 0 ) );
677 not matching_signs ) {
678
679 return exponent_p1 + exponent_p2;
680 }
681 signed_t const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
682 if( s < 0 ) {
683 if( DAW_UNLIKELY( ( daw::lowest_value<signed_t> - exponent_p1 ) >
684 exponent_p2 ) ) {
685 // We don't have inf, but we can just saturate it to min as it
686 // will be 0 anyways for the other result
687 return daw::lowest_value<signed_t>;
688 }
689 return exponent_p1 + exponent_p2;
690 }
691 auto const r = static_cast<unsigned_t>( exponent_p1 ) +
692 static_cast<unsigned_t>( exponent_p2 );
693 if( DAW_UNLIKELY(
694 r > static_cast<unsigned_t>( daw::max_value<signed_t> ) ) ) {
695 return daw::max_value<signed_t>;
696 }
697 return static_cast<signed_t>( r );
698 }
699 }( );
700 parse_state.first = first;
701
702 if constexpr( std::is_floating_point_v<Result> and
703 ParseState::precise_ieee754 ) {
704 // long double that shares double's size/precision/exponent range
705 // (e.g. MSVC) is computed as double instead, since Eisel-Lemire
706 // only supports binary32/binary64.
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;
716
717 DAW_CPP23_STATIC_LOCAL constexpr int pow10_threshold =
718 is_80bit_long_double_v ? 27
719 : is_128bit_long_double_v ? 48
720 : 22;
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>));
726 }
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,
732 significant_digits,
733 exponent );
734 discarded_nonzero |=
735 append_discarded_digits( discarded_fract_first,
736 discarded_fract_last,
737 significant_digits,
738 exponent );
739 using compute_t =
740 std::conditional_t<std::is_same_v<Result, long double>,
741 double,
742 Result>;
743 return static_cast<Result>(
744 parse_truncated_lemire<compute_t>( sign < 0,
745 exponent,
746 significant_digits,
747 discarded_nonzero,
748 orig_first.get( ),
749 first.get( ) ) );
750 } else {
751 static_assert( std::is_same_v<Result, long double> );
752 return json_details::parse_with_strtod<Result>( orig_first.get( ),
753 first.get( ) );
754 }
755 }
756 }
757 return static_cast<Result>( sign ) *
758 power10<Result>( ParseState::exec_tag,
759 static_cast<Result>( significant_digits ),
760 exponent );
761 }
762
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 );
767 } else {
768 return parse_real_unknown<Result>( parse_state );
769 }
770 }
771 } // namespace json_details
772 } // namespace DAW_JSON_VER
773} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20