21 #include <daw/daw_cxmath.h>
22 #include <daw/daw_likely.h>
23 #include <daw/daw_restrict.h>
24 #include <daw/daw_utility.h>
29 #include <type_traits>
33 namespace json_details {
34 template<
bool skip_end_check,
typename Un
signed>
36 DAW_ATTRIB_FLATINLINE
inline constexpr
void parse_digits_until_last(
37 char const *DAW_RESTRICT first,
char const *
const DAW_RESTRICT last,
38 Unsigned &DAW_RESTRICT v ) {
40 if constexpr( skip_end_check ) {
41 auto dig = parse_digit( *first );
46 dig = parse_digit( *first );
49 while( DAW_LIKELY( first < last ) ) {
51 value += parse_digit( *first );
58 template<
bool skip_end_check,
typename Un
signed,
typename CharT>
59 [[nodiscard]] DAW_ATTRIB_NONNULL( ) DAW_ATTRIB_FLATINLINE
60 inline constexpr CharT *parse_digits_while_number(
61 CharT *DAW_RESTRICT first, CharT *
const DAW_RESTRICT last,
62 Unsigned &DAW_RESTRICT v ) {
69 if constexpr( skip_end_check ) {
70 for(
auto dig = parse_digit( *first ); dig < 10U;
71 ++first, dig = parse_digit( *first ) ) {
77 unsigned dig = parse_digit( *first );
82 if( DAW_UNLIKELY( first == last ) ) {
85 dig = parse_digit( *first );
95 template<
typename ParseState,
typename Result,
96 typename max_storage_digits,
typename CharT>
97 DAW_ATTRIB_NONNULL( ( 1, 2 ) )
98 [[nodiscard]]
inline constexpr
bool should_use_strtod(
99 CharT *whole_first, CharT *whole_last, CharT *fract_first,
100 CharT *fract_last ) {
101 if constexpr( std::is_floating_point_v<Result> and
102 ParseState::precise_ieee754 ) {
104 ( ( whole_last - whole_first ) +
105 ( fract_first ? fract_last - fract_first : 0 ) ) >
106 max_storage_digits::value );
117 template<
typename Result,
typename ParseState>
118 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
119 parse_real_known( ParseState &parse_state ) {
120 using CharT =
typename ParseState::CharT;
123 parse_state.has_more( ) and
124 parse_policy_details::is_number_start( parse_state.front( ) ),
125 ErrorReason::InvalidNumberStart, parse_state );
127 CharT *whole_first = parse_state.first;
128 CharT *whole_last = parse_state.class_first ? parse_state.class_first
129 : parse_state.class_last;
131 parse_state.class_first ? parse_state.class_first + 1 :
nullptr;
132 CharT *fract_last = parse_state.class_last;
134 parse_state.class_last ? parse_state.class_last + 1 :
nullptr;
135 CharT *
const exp_last = parse_state.last;
137 if( parse_state.class_first ==
nullptr ) {
138 if( parse_state.class_last ==
nullptr ) {
139 whole_last = parse_state.last;
141 whole_last = parse_state.class_last;
143 }
else if( parse_state.class_last ==
nullptr ) {
144 fract_last = parse_state.last;
147 using max_storage_digits = daw::constant<static_cast<std::ptrdiff_t>(
148 daw::numeric_limits<std::uint64_t>::digits10 )>;
151 should_use_strtod<ParseState, Result, max_storage_digits>(
152 whole_first, whole_last, fract_first, fract_last );
154 Result
const sign = [&] {
155 if( *whole_first ==
'-' ) {
157 return static_cast<Result
>( -1.0 );
159 return static_cast<Result
>( 1.0 );
161 using max_exponent = daw::constant<static_cast<std::ptrdiff_t>(
162 daw::numeric_limits<Result>::max_digits10 + 1 )>;
164 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
165 std::uint64_t, Result>;
168 typename daw::conditional_t<std::is_floating_point_v<unsigned_t>,
169 daw::traits::identity<unsigned_t>,
170 std::make_signed<unsigned_t>>::type;
171 std::intmax_t whole_exponent_available = whole_last - whole_first;
172 std::intmax_t fract_exponent_available =
173 fract_first ? fract_last - fract_first : 0;
174 signed_t exponent = 0;
176 if( whole_exponent_available > max_exponent::value ) {
177 whole_last = whole_first + max_exponent::value;
178 whole_exponent_available -= max_exponent::value;
179 fract_exponent_available = 0;
180 fract_first =
nullptr;
181 exponent = whole_exponent_available;
183 whole_exponent_available =
184 max_exponent::value - whole_exponent_available;
185 if constexpr( ParseState::precise_ieee754 ) {
186 use_strtod |= DAW_UNLIKELY( fract_exponent_available >
187 whole_exponent_available );
189 if( whole_exponent_available < fract_exponent_available ) {
190 fract_exponent_available = whole_exponent_available;
192 exponent = -fract_exponent_available;
193 fract_last = fract_first + fract_exponent_available;
196 unsigned_t significant_digits = 0;
198 ParseState::is_unchecked_input )>(
199 whole_first, whole_last, significant_digits );
202 ParseState::is_unchecked_input )>(
203 fract_first, fract_last, significant_digits );
206 if( exp_first and ( exp_last - exp_first ) > 0 ) {
207 signed_t
const exp_sign = [&] {
208 switch( *exp_first ) {
212 ErrorReason::InvalidNumber );
216 ErrorReason::InvalidNumber );
223 exponent += to_signed(
225 unsigned_t exp_result = 0;
227 auto dig = parse_digit( *exp_first );
232 dig = parse_digit( *exp_first );
235 if( exp_first < exp_last ) {
236 auto dig = parse_digit( *exp_first );
244 if( exp_first >= exp_last ) {
247 dig = parse_digit( *exp_first );
255 if constexpr( std::is_floating_point_v<Result> and
256 ParseState::precise_ieee754 ) {
260 use_strtod |= exponent > 22;
261 use_strtod |= exponent < -22;
262 use_strtod |= significant_digits > 9007199254740992ULL;
263 if constexpr( std::is_same_v<Result, long double> ) {
264 return json_details::parse_with_strtod<Result>( parse_state.first,
267 if( DAW_UNLIKELY( use_strtod ) ) {
268 return json_details::parse_with_strtod<Result>(
269 parse_state.first, parse_state.last );
273 return sign * power10<Result>(
274 ParseState::exec_tag,
275 static_cast<Result
>( significant_digits ), exponent );
278 template<
typename Result,
typename ParseState>
279 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Result
280 parse_real_unknown( ParseState &parse_state ) {
282 using CharT =
typename ParseState::CharT;
284 parse_state.has_more( ) and
285 parse_policy_details::is_number_start( parse_state.front( ) ),
286 ErrorReason::InvalidNumberStart, parse_state );
288 CharT *
const orig_first = parse_state.first;
289 CharT *
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::numeric_limits<std::uint64_t>::digits10 )>;
301 using max_exponent = daw::constant<static_cast<std::int64_t>(
302 daw::numeric_limits<Result>::max_digits10 + 1 )>;
304 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
305 std::uint64_t, Result>;
307 daw::conditional_t<max_storage_digits::value >= max_exponent::value,
308 std::int64_t, Result>;
310 CharT *first = parse_state.first;
311 CharT *
const whole_last =
313 ( std::min )( parse_state.last - parse_state.first,
314 static_cast<std::ptrdiff_t
>( max_exponent::value ) );
316 unsigned_t significant_digits = 0;
319 ParseState::is_unchecked_input )>(
320 first, whole_last, significant_digits );
321 std::ptrdiff_t sig_digit_count = last_char - parse_state.first;
323 std::is_floating_point_v<Result> and ParseState::precise_ieee754 and
324 DAW_UNLIKELY( sig_digit_count > max_storage_digits::value );
325 signed_t exponent_p1 = [&] {
326 if( DAW_UNLIKELY( last_char >= whole_last ) ) {
327 if constexpr( std::is_floating_point_v<Result> and
328 ParseState::precise_ieee754 ) {
334 ParseState::is_unchecked_input )>(
335 last_char, parse_state.last );
336 auto const diff = ptr - last_char;
339 if( significant_digits == 0 ) {
340 return signed_t{ 0 };
342 return static_cast<signed_t
>( diff );
344 return signed_t{ 0 };
349 ParseState::is_unchecked_input or
350 DAW_LIKELY( first < parse_state.last ) ) and
353 if( exponent_p1 != 0 ) {
354 if( first < parse_state.last ) {
356 ParseState::is_unchecked_input )>(
357 first, parse_state.last );
361 first + ( std::min )( parse_state.last - first,
362 static_cast<std::ptrdiff_t
>(
363 max_exponent::value -
364 ( first - parse_state.first ) ) );
366 last_char = parse_digits_while_number<(
368 ParseState::is_unchecked_input )>( first, fract_last,
369 significant_digits );
370 sig_digit_count += last_char - first;
371 exponent_p1 -=
static_cast<signed_t
>( last_char - first );
373 if( ( first >= fract_last ) & ( first < parse_state.last ) ) {
376 ParseState::is_unchecked_input )>(
377 first, parse_state.last );
378 if constexpr( std::is_floating_point_v<Result> and
379 ParseState::precise_ieee754 ) {
380 use_strtod |= new_first > first;
387 signed_t
const exponent_p2 = [&] {
388 if( ( ParseState::is_unchecked_input or first < parse_state.last ) and
389 ( ( *first | 0x20 ) ==
'e' ) ) {
391 signed_t
const exp_sign = [&] {
393 first < parse_state.last ),
394 ErrorReason::UnexpectedEndOfData,
395 parse_state.copy( first ) );
400 ( parse_digit( *first ) < 10U ),
401 ErrorReason::InvalidNumber );
402 return signed_t{ 1 };
406 parse_digit( *first ) < 10U,
407 ErrorReason::InvalidNumber );
408 return signed_t{ -1 };
411 ErrorReason::InvalidNumber );
412 return signed_t{ 1 };
416 ErrorReason::UnexpectedEndOfData,
418 unsigned_t exp_tmp = 0;
419 last_char = parse_digits_while_number<(
421 ParseState::is_unchecked_input )>( first, parse_state.last,
424 return to_signed( exp_tmp, exp_sign );
426 return signed_t{ 0 };
428 signed_t
const exponent = [&] {
429 if constexpr( ParseState::is_unchecked_input or
430 not std::is_floating_point_v<Result> ) {
431 return exponent_p1 + exponent_p2;
433 if(
bool matching_signs =
434 ( exponent_p1 < 0 ) == ( exponent_p2 < 0 );
435 not matching_signs ) {
437 return exponent_p1 + exponent_p2;
439 auto const s = exponent_p1 < 0 ? signed_t{ -1 } : signed_t{ 1 };
441 if( DAW_UNLIKELY( ( daw::numeric_limits<signed_t>::min( ) -
442 exponent_p1 ) > exponent_p2 ) ) {
445 return daw::numeric_limits<signed_t>::min( );
447 return exponent_p1 + exponent_p2;
449 auto r =
static_cast<unsigned_t
>( exponent_p1 ) +
450 static_cast<unsigned_t
>( exponent_p2 );
452 r >
static_cast<unsigned_t
>(
453 ( daw::numeric_limits<signed_t>::max )( ) ) ) ) {
454 return ( daw::numeric_limits<signed_t>::max )( );
456 return static_cast<signed_t
>( r );
459 parse_state.first = first;
461 if constexpr( std::is_floating_point_v<Result> and
462 ParseState::precise_ieee754 ) {
463 use_strtod |= DAW_UNLIKELY( exponent > 22 );
464 use_strtod |= DAW_UNLIKELY( exponent < -22 );
466 DAW_UNLIKELY( significant_digits > 9007199254740992ULL );
467 if( DAW_UNLIKELY( use_strtod ) ) {
468 using json_details::parse_with_strtod;
469 auto result = parse_with_strtod<Result>( orig_first, orig_last );
476 return sign * power10<Result>(
477 ParseState::exec_tag,
478 static_cast<Result
>( significant_digits ), exponent );
481 template<
typename Result,
bool KnownRange,
typename ParseState>
482 [[nodiscard]]
static constexpr Result
483 parse_real( ParseState &parse_state ) {
484 if constexpr( KnownRange ) {
485 return parse_real_known<Result>( parse_state );
487 return parse_real_unknown<Result>( parse_state );
#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.
constexpr bool is_number(char c)
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.