34 namespace json_details {
35 template<
bool skip_end_check,
typename Un
signed>
36 DAW_ATTRIB_FLATINLINE
constexpr void parse_digits_until_last(
37 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_NONNULL( ) DAW_ATTRIB_FLATINLINE
61 constexpr daw::not_null<char const *> parse_digits_while_number(
62 daw::not_null<char const *> first,
63 daw::not_null<char const *>
const last,
64 Unsigned &DAW_RESTRICT v ) {
71 if constexpr( skip_end_check ) {
72 for(
auto dig = parse_digit( *first ); dig < 10U;
73 ++first, dig = parse_digit( *first ) ) {
79 auto dig = parse_digit( *first );
84 if( DAW_UNLIKELY( first == last ) ) {
87 dig = parse_digit( *first );
97 template<
typename ParseState,
typename Result,
98 typename max_storage_digits>
99 [[nodiscard]]
constexpr bool
100 should_use_strtod( daw::not_null<char const *> whole_first,
101 daw::not_null<char const *>
const whole_last,
102 char const *fract_first,
char const *fract_last ) {
103 if constexpr( std::is_floating_point_v<Result> and
104 ParseState::precise_ieee754 ) {
106 ( ( whole_last - whole_first ) +
107 ( fract_first ? fract_last - fract_first : 0 ) ) >
108 max_storage_digits::value );
119 template<
typename Result,
typename ParseState>
120 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
121 parse_real_known( ParseState &parse_state ) {
124 parse_state.has_more( ) and
125 parse_policy_details::is_number_start( parse_state.front( ) ),
126 ErrorReason::InvalidNumberStart,
129 daw::not_null<char const *> whole_first = parse_state.first;
130 char const *whole_last = parse_state.class_first
131 ? parse_state.class_first
132 : parse_state.class_last;
133 char const *fract_first =
134 parse_state.class_first ? parse_state.class_first + 1 :
nullptr;
135 char const *fract_last = parse_state.class_last;
136 char const *exp_first =
137 parse_state.class_last ? parse_state.class_last + 1 :
nullptr;
138 daw::not_null<char const *>
const exp_last = parse_state.last;
140 if( parse_state.class_first ==
nullptr ) {
141 if( parse_state.class_last ==
nullptr ) {
142 whole_last = parse_state.last;
144 whole_last = parse_state.class_last;
146 }
else if( parse_state.class_last ==
nullptr ) {
147 fract_last = parse_state.last;
150 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
151 daw::digits10<std::uint64_t> )>;
154 should_use_strtod<ParseState, Result, max_storage_digits>(
155 whole_first, whole_last, fract_first, fract_last );
157 Result
const sign = [&] {
158 if( *whole_first ==
'-' ) {
160 return static_cast<Result
>( -1.0 );
162 return static_cast<Result
>( 1.0 );
164 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
165 daw::max_digits10<Result> + 1 )>;
167 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
172 typename daw::conditional_t<std::is_floating_point_v<unsigned_t>,
173 daw::traits::identity<unsigned_t>,
174 std::make_signed<unsigned_t>>::type;
175 std::intmax_t whole_exponent_available = whole_last - whole_first;
176 std::intmax_t fract_exponent_available =
177 fract_first ? fract_last - fract_first : 0;
178 signed_t exponent = 0;
180 if( whole_exponent_available > max_exponent::value ) {
181 whole_last = whole_first + max_exponent::value;
182 whole_exponent_available -= max_exponent::value;
183 fract_exponent_available = 0;
184 fract_first =
nullptr;
185 exponent = whole_exponent_available;
187 whole_exponent_available =
188 max_exponent::value - whole_exponent_available;
189 if constexpr( ParseState::precise_ieee754 ) {
190 use_strtod |= DAW_UNLIKELY( fract_exponent_available >
191 whole_exponent_available );
193 if( whole_exponent_available < fract_exponent_available ) {
194 fract_exponent_available = whole_exponent_available;
196 exponent = -fract_exponent_available;
197 fract_last = fract_first + fract_exponent_available;
200 unsigned_t significant_digits = 0;
201 parse_digits_until_last<( ParseState::is_zero_terminated_string or
202 ParseState::is_unchecked_input )>(
203 whole_first, whole_last, significant_digits );
205 parse_digits_until_last<( ParseState::is_zero_terminated_string or
206 ParseState::is_unchecked_input )>(
207 fract_first, fract_last, significant_digits );
210 if( exp_first and ( exp_last - exp_first ) > 0 ) {
211 signed_t
const exp_sign = [&] {
212 switch( *exp_first ) {
216 ErrorReason::InvalidNumber );
220 ErrorReason::InvalidNumber );
227 exponent += to_signed(
229 unsigned_t exp_result = 0;
230 if constexpr( ParseState::is_zero_terminated_string ) {
231 auto dig = parse_digit( *exp_first );
236 dig = parse_digit( *exp_first );
239 if( exp_first < exp_last ) {
240 auto dig = parse_digit( *exp_first );
248 if( exp_first >= exp_last ) {
251 dig = parse_digit( *exp_first );
259 if constexpr( std::is_floating_point_v<Result> and
260 ParseState::precise_ieee754 ) {
264 use_strtod |= exponent > 22;
265 use_strtod |= exponent < -22;
266 use_strtod |= significant_digits > 9007199254740992ULL;
267 if( std::is_same_v<Result, long double> or
268 DAW_UNLIKELY( use_strtod ) ) {
269 return json_details::parse_with_strtod<Result>( parse_state.first,
274 power10<Result>( ParseState::exec_tag,
275 static_cast<Result
>( significant_digits ),
279 template<
typename Result,
typename ParseState>
280 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
281 parse_real_unknown( ParseState &parse_state ) {
284 parse_state.has_more( ) and
285 parse_policy_details::is_number_start( parse_state.front( ) ),
286 ErrorReason::InvalidNumberStart,
289 daw::not_null<char const *>
const orig_first = parse_state.first;
290 daw::not_null<char const *>
const orig_last = parse_state.last;
297 auto const sign =
static_cast<Result
>(
298 parse_policy_details::validate_signed_first( parse_state ) );
300 using max_storage_digits = daw::constant<static_cast<std::int64_t>(
301 daw::digits10<std::uint64_t> )>;
302 using max_exponent = daw::constant<static_cast<std::int64_t>(
303 daw::max_digits10<Result> + 1 )>;
305 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
309 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
313 daw::not_null<char const *> first = parse_state.first;
314 daw::not_null<char const *>
const last = parse_state.last;
315 daw::not_null<char const *>
const whole_last =
317 (std::min)( parse_state.last - parse_state.first,
318 static_cast<std::ptrdiff_t
>( max_exponent::value ) );
320 unsigned_t significant_digits = 0;
321 daw::not_null<char const *> last_char =
322 parse_digits_while_number<( ParseState::is_zero_terminated_string or
323 ParseState::is_unchecked_input )>(
324 first.get( ), whole_last.get( ), significant_digits );
325 auto sig_digit_count = last_char - parse_state.first;
327 std::is_floating_point_v<Result> and ParseState::precise_ieee754 and
328 DAW_UNLIKELY( sig_digit_count > max_storage_digits::value );
329 signed_t exponent_p1 = [&] {
330 if( DAW_UNLIKELY( last_char >= whole_last ) ) {
331 if constexpr( std::is_floating_point_v<Result> and
332 ParseState::precise_ieee754 ) {
337 daw::not_null<char const *> ptr =
338 skip_digits<( ParseState::is_zero_terminated_string or
339 ParseState::is_unchecked_input )>( last_char,
341 auto const diff = ptr - last_char;
344 if( significant_digits == 0 ) {
345 return signed_t{ 0 };
347 return static_cast<signed_t
>( diff );
349 return signed_t{ 0 };
353 if( ( ParseState::is_zero_terminated_string or
354 ParseState::is_unchecked_input or
355 DAW_LIKELY( first < parse_state.last ) ) and
358 if( exponent_p1 != 0 ) {
359 if( first < parse_state.last ) {
361 skip_digits<( ParseState::is_zero_terminated_string or
362 ParseState::is_unchecked_input )>( first, last );
365 daw::not_null<char const *> fract_last =
366 first + (std::min)( parse_state.last - first,
367 static_cast<std::ptrdiff_t
>(
368 max_exponent::value -
369 ( first - parse_state.first ) ) );
371 last_char = parse_digits_while_number<(
372 ParseState::is_zero_terminated_string or
373 ParseState::is_unchecked_input )>(
374 first.get( ), fract_last.get( ), significant_digits );
375 sig_digit_count += last_char - first;
376 exponent_p1 -=
static_cast<signed_t
>( last_char - first );
378 if( daw::nsc_and( first >= fract_last, first < last ) ) {
380 skip_digits<( ParseState::is_zero_terminated_string or
381 ParseState::is_unchecked_input )>( first, last );
382 if constexpr( std::is_floating_point_v<Result> and
383 ParseState::precise_ieee754 ) {
384 use_strtod |= new_first > first;
391 signed_t
const exponent_p2 = [&] {
392 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
393 ( ( *first | 0x20 ) ==
'e' ) ) {
395 signed_t
const exp_sign = [&] {
397 first < parse_state.last ),
398 ErrorReason::UnexpectedEndOfData,
399 parse_state.copy( first ) );
404 ( parse_digit( *first ) < 10U ),
405 ErrorReason::InvalidNumber );
406 return signed_t{ 1 };
410 parse_digit( *first ) < 10U,
411 ErrorReason::InvalidNumber );
412 return signed_t{ -1 };
415 ErrorReason::InvalidNumber );
416 return signed_t{ 1 };
420 ErrorReason::UnexpectedEndOfData,
422 unsigned_t exp_tmp = 0;
423 using skip_end_check =
424 std::bool_constant<ParseState::is_zero_terminated_string or
425 ParseState::is_unchecked_input>;
426 last_char = parse_digits_while_number<skip_end_check::value>(
427 first.get( ), last.get( ), exp_tmp );
429 return to_signed( exp_tmp, exp_sign );
431 return signed_t{ 0 };
433 auto const exponent = [&] {
434 if constexpr( ParseState::is_unchecked_input or
435 not std::is_floating_point_v<Result> ) {
436 return exponent_p1 + exponent_p2;
438 if(
bool const matching_signs =
439 ( ( exponent_p1 < 0 ) == ( exponent_p2 < 0 ) );
440 not matching_signs ) {
442 return exponent_p1 + exponent_p2;
444 auto const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
446 if( DAW_UNLIKELY( ( daw::min_value<signed_t> - exponent_p1 ) >
450 return daw::min_value<signed_t>;
452 return exponent_p1 + exponent_p2;
454 auto const r =
static_cast<unsigned_t
>( exponent_p1 ) +
455 static_cast<unsigned_t
>( exponent_p2 );
457 r >
static_cast<unsigned_t
>( daw::max_value<signed_t> ) ) ) {
458 return daw::max_value<signed_t>;
460 return static_cast<signed_t
>( r );
463 parse_state.first = first;
465 if constexpr( std::is_floating_point_v<Result> and
466 ParseState::precise_ieee754 ) {
467 use_strtod |= DAW_UNLIKELY( exponent > 22 );
468 use_strtod |= DAW_UNLIKELY( exponent < -22 );
470 DAW_UNLIKELY( significant_digits > 9007199254740992ULL );
471 if( DAW_UNLIKELY( use_strtod ) ) {
472 using json_details::parse_with_strtod;
473 auto result = parse_with_strtod<Result>( orig_first, orig_last );
481 power10<Result>( ParseState::exec_tag,
482 static_cast<Result
>( significant_digits ),
486 template<
typename Result,
bool KnownRange,
typename ParseState>
487 [[nodiscard]]
constexpr Result parse_real( ParseState &parse_state ) {
488 if constexpr( KnownRange ) {
489 return parse_real_known<Result>( parse_state );
491 return parse_real_unknown<Result>( parse_state );