14#if defined( DAW_JSON_HAS_SIMD )
29 namespace json_details::simd_details {
35 struct simd_class_structural_state {
36 using simd_type = daw::simd::vec<char>;
37 static constexpr std::size_t block_size =
38 static_cast<std::size_t
>( simd_type::size( ) );
39 static_assert( block_size <= 64U );
41 char const *next_block =
nullptr;
42 char const *last =
nullptr;
43 char const *block_data =
nullptr;
44 std::size_t block_length = 0U;
47 std::uint64_t structural_offsets = 0U;
48 bool in_string =
false;
51 constexpr void reset(
char const *first,
char const *last_ptr ) {
56 structural_offsets = 0U;
62 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR
bool classify_next_block( ) {
63 if( next_block ==
nullptr or next_block >= last ) {
67 block_data = next_block;
68 auto const remaining =
static_cast<std::size_t
>( last - next_block );
69 block_length = remaining < block_size ? remaining : block_size;
70 auto const input = simd_details::load<simd_type, block_size, char>(
71 block_data, block_length );
72 auto const valid_bits = simd_details::low_bits( block_length );
73 auto const backslash_bits =
74 ( input == simd_details::splat<simd_type>(
'\\' ) ).to_ullong( ) &
77 DAW_CPP23_STATIC_LOCAL
constexpr std::uint64_t odd_bits =
78 0xAAAAAAAAAAAAAAAAULL;
79 auto const previous_escaped = escaped ? std::uint64_t{ 1 } : 0U;
80 auto const potential_escape = backslash_bits & ~previous_escaped;
81 auto const maybe_escaped = potential_escape << 1U;
82 auto const escape_and_terminal =
83 ( ( maybe_escaped | odd_bits ) - potential_escape ) ^ odd_bits;
84 auto const escaped_bits =
85 ( escape_and_terminal ^ ( backslash_bits | previous_escaped ) ) &
87 auto const escape_bits = escape_and_terminal & backslash_bits;
88 escaped = simd_details::last_bit( escape_bits, block_length );
90 auto const quote_bits =
91 ( input == simd_details::splat<simd_type>(
'"' ) ).to_ullong( ) &
92 ~escaped_bits & valid_bits;
93 auto const in_string_bits =
94 ( simd_details::prefix_xor( quote_bits ) ^
95 ( in_string ? valid_bits : std::uint64_t{ 0 } ) ) &
97 in_string = simd_details::last_bit( in_string_bits, block_length );
99 auto const outside_string_bits =
100 ~( in_string_bits ^ quote_bits ) & valid_bits;
101 auto const json_structurals =
102 simd_details::one_of<
'{',
'}',
'[',
']',
':',
','>( input )
105 auto const number_metadata =
106 simd_details::one_of<
'.',
'e',
'E'>( input ).to_ullong( ) &
109 quote_bits | backslash_bits | json_structurals | number_metadata;
110 next_block +=
static_cast<std::ptrdiff_t
>( block_length );
115 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR
char const *
116 next(
char const *minimum ) {
118 while( structural_offsets != 0U ) {
119 auto const lane =
static_cast<std::size_t
>(
120 daw::cxmath::count_trailing_zeros( structural_offsets ) );
121 structural_offsets &= structural_offsets - 1U;
122 auto const result = block_data + lane;
123 if( result >= minimum ) {
127 if( not classify_next_block( ) ) {
134 [[nodiscard]]
constexpr bool is_json_whitespace(
char value )
noexcept {
135 return value ==
' ' or value ==
'\t' or value ==
'\n' or value ==
'\r';
138 [[nodiscard]]
constexpr char const *
139 trim_value_right(
char const *first,
char const *last )
noexcept {
140 while( last > first and is_json_whitespace( last[-1] ) ) {
146 template<std::
size_t N>
147 [[nodiscard]]
constexpr bool
148 matches_literal(
char const *first,
char const *last,
149 char const ( &literal )[N] )
noexcept {
150 if(
static_cast<std::size_t
>( last - first ) != N - 1U ) {
153 for( std::size_t n = 0;
n < N - 1U; ++
n ) {
154 if( first[n] != literal[n] ) {
161 template<
typename JsonMemberList>
162 struct simd_class_parser;
164 template<
typename... JsonMembers>
165 struct simd_class_parser<json_member_list<JsonMembers...>> {
166 template<
typename ParseState>
167 using locations_type =
168 decltype( make_locations_info<ParseState, JsonMembers...>( ) );
170 template<
typename ParseState>
171 [[nodiscard]]
static constexpr locations_type<ParseState>
173 return make_locations_info<ParseState, JsonMembers...>( );
176 template<
typename JsonClass,
typename ParseState>
177 [[nodiscard]]
static DAW_JSON_SIMD_CONSTEXPR
char const *
178 scan_class( ParseState &parse_state,
179 locations_type<ParseState> &locations,
180 simd_class_structural_state &structural_state ) {
181 using result_t = json_result_t<JsonClass>;
182 DAW_CPP23_STATIC_LOCAL
constexpr bool must_exist =
183 all_json_members_must_exist_v<result_t, ParseState>;
185 parse_state.trim_left( );
187 ErrorReason::InvalidClassStart,
189 auto const old_class_pos = parse_state.get_class_position( );
190 auto const class_first = parse_state.data( );
191 auto const class_last = parse_state.data_end( );
192 parse_state.set_class_position( );
194 auto event = structural_state.next( class_first );
196 ErrorReason::InvalidClassStart,
198 event = structural_state.next( event + 1 );
199 auto after_comma =
false;
201 while( event !=
nullptr and *event !=
'}' ) {
203 ErrorReason::InvalidMemberName,
205 auto const name_first =
event + 1;
206 auto name_last = structural_state.next( name_first );
207 while( name_last !=
nullptr and *name_last ==
'\\' ) {
208 name_last = structural_state.next( name_last + 1 );
211 ErrorReason::InvalidMemberName,
213 auto const name = daw::string_view(
214 name_first,
static_cast<std::size_t
>( name_last - name_first ) );
215 auto const name_pos =
216 locations.template find_name<ParseState::expect_long_strings, 0>(
218 if constexpr( must_exist ) {
220 ErrorReason::UnknownMember,
223 auto const colon = structural_state.next( name_last + 1 );
225 ErrorReason::InvalidMemberName,
227 auto value_state = ParseState( colon + 1, class_last );
228 value_state.trim_left( );
229 auto const value_first = value_state.data( );
231 ErrorReason::UnexpectedEndOfData,
234 auto object_depth = std::size_t{ 1 };
235 auto array_depth = std::size_t{ 0 };
236 auto container_count = std::size_t{ 0 };
237 char const *first_escape =
nullptr;
238 char const *string_last =
nullptr;
239 char const *decimal_point =
nullptr;
240 char const *exponent_marker =
nullptr;
241 auto const value_is_string = *value_first ==
'"';
242 auto const value_is_array = *value_first ==
'[';
243 auto const value_is_class = *value_first ==
'{';
244 auto const value_is_number =
245 *value_first ==
'-' or
246 ( *value_first >=
'0' and *value_first <=
'9' );
247 auto delimiter = structural_state.next( colon + 1 );
248 auto found_delimiter =
false;
249 while( value_is_number and delimiter !=
nullptr and
250 not found_delimiter ) {
251 switch( *delimiter ) {
253 if( decimal_point ==
nullptr ) {
254 decimal_point = delimiter;
259 if( exponent_marker ==
nullptr ) {
260 exponent_marker = delimiter;
264 found_delimiter =
true;
267 if( not found_delimiter ) {
268 delimiter = structural_state.next( delimiter + 1 );
271 while( not value_is_number and delimiter !=
nullptr and
272 not found_delimiter ) {
273 switch( *delimiter ) {
275 if( value_is_string and delimiter != value_first and
276 string_last ==
nullptr ) {
277 string_last = delimiter;
281 if( value_is_string and first_escape ==
nullptr ) {
282 first_escape = delimiter;
289 if( object_depth == 1U and array_depth == 0U ) {
290 found_delimiter =
true;
294 ErrorReason::InvalidBracketing,
303 ErrorReason::InvalidBracketing,
308 if( ( value_is_array and object_depth == 1U and
309 array_depth == 1U ) or
310 ( value_is_class and object_depth == 2U and
311 array_depth == 0U ) ) {
314 if( object_depth == 1U and array_depth == 0U ) {
315 found_delimiter =
true;
321 if( not found_delimiter ) {
322 delimiter = structural_state.next( delimiter + 1 );
327 ErrorReason::UnexpectedEndOfData,
329 auto const value_last =
330 trim_value_right( value_first, delimiter );
332 ErrorReason::InvalidStartOfValue,
334 if constexpr( not ParseState::is_unchecked_input ) {
335 switch( *value_first ) {
338 matches_literal( value_first, value_last,
"true" ),
339 ErrorReason::InvalidTrue,
344 matches_literal( value_first, value_last,
"false" ),
345 ErrorReason::InvalidFalse,
350 matches_literal( value_first, value_last,
"null" ),
351 ErrorReason::InvalidNull,
359 if( name_pos < locations.size( ) and
360 locations[name_pos].missing( ) ) {
361 auto location_state = ParseState(
362 value_first, value_last, class_first, class_last );
363 switch( *value_first ) {
366 string_last + 1 == value_last,
367 ErrorReason::InvalidString,
369 location_state.first = value_first + 1;
370 location_state.last = string_last;
371 location_state.counter =
372 first_escape ==
nullptr
373 ?
static_cast<std::size_t
>( -1 )
374 : static_cast<
std::size_t>( first_escape - ( value_first + 1 ) );
377 location_state.counter = 1U;
380 location_state.counter = 0U;
383 location_state.first =
nullptr;
384 location_state.last =
nullptr;
388 location_state.counter = container_count;
391 location_state.class_first = decimal_point;
392 location_state.class_last = exponent_marker;
395 locations[name_pos].set_range( location_state );
396 }
else if constexpr( must_exist ) {
400 after_comma = *delimiter ==
',';
402 ? structural_state.next( delimiter + 1 )
407 ErrorReason::UnexpectedEndOfData,
410 ErrorReason::TrailingComma,
413 ErrorReason::InvalidEndOfValue,
415 auto const class_end =
event + 1;
416 parse_state.first = class_end;
417 parse_state.trim_left_checked( );
418 parse_state.set_class_position( old_class_pos );
423 template<
typename JsonMember,
typename ParseState,
typename Location>
424 [[nodiscard]]
static constexpr json_result_t<JsonMember>
425 parse_member( ParseState &parse_state, Location
const &location ) {
426 auto member_state = [&] {
427 if constexpr( ParseState::has_allocator ) {
428 return location.template get_range<ParseState>( ).with_allocator(
431 return location.template get_range<ParseState>( );
434 if( member_state.is_null( ) ) {
437 return parse_class_member_impl<JsonMember, false>(
438 parse_state, find_result<ParseState>{ member_state,
true } );
440 return parse_value<without_name<JsonMember>,
442 JsonMember::expected_type>( member_state );
445 template<
typename JsonClass,
typename ParseState, std::size_t... Is>
446 [[nodiscard]]
static constexpr json_result_t<JsonClass>
447 construct_class_impl( ParseState &parse_state,
448 locations_type<ParseState>
const &locations,
449 std::index_sequence<Is...> ) {
450 using result_t = json_result_t<JsonClass>;
451 using constructor_t = json_constructor_t<JsonClass>;
456 parse_member<JsonMembers>( parse_state, locations[Is] )... };
458 return construct_value_tp<result_t, constructor_t>(
461 parse_member<JsonMembers>( parse_state, locations[Is] )... } );
466 template<
typename JsonClass,
typename ParseState>
467 [[nodiscard]]
static constexpr json_result_t<JsonClass>
468 construct_class( ParseState &parse_state,
469 locations_type<ParseState>
const &locations ) {
470 return construct_class_impl<JsonClass>(
473 std::index_sequence_for<JsonMembers...>{ } );
478 struct simd_class_parser<json_member_list<>> {
479 struct empty_locations {};
481 template<
typename ParseState>
482 using locations_type = empty_locations;
484 template<
typename ParseState>
485 [[nodiscard]]
static constexpr locations_type<ParseState>
490 template<
typename JsonClass,
typename ParseState>
491 [[nodiscard]]
static DAW_JSON_SIMD_CONSTEXPR
char const *
492 scan_class( ParseState &parse_state, empty_locations &,
493 simd_class_structural_state &structural_state ) {
494 using result_t = json_result_t<JsonClass>;
495 parse_state.trim_left( );
497 ErrorReason::InvalidClassStart,
499 auto const old_class_pos = parse_state.get_class_position( );
500 auto const class_first = parse_state.data( );
501 parse_state.set_class_position( );
502 auto event = structural_state.next( class_first );
504 ErrorReason::InvalidClassStart,
506 event = structural_state.next( event + 1 );
507 if constexpr( all_json_members_must_exist_v<result_t, ParseState> ) {
509 ErrorReason::UnknownMember,
512 auto object_depth = std::size_t{ 1 };
513 auto array_depth = std::size_t{ 0 };
514 auto found_end =
false;
515 while( event !=
nullptr and not found_end ) {
521 if( object_depth == 1U and array_depth == 0U ) {
526 ErrorReason::InvalidBracketing,
535 ErrorReason::InvalidBracketing,
542 if( not found_end ) {
543 event = structural_state.next( event + 1 );
547 ErrorReason::UnexpectedEndOfData,
550 auto const class_end =
event + 1;
551 parse_state.first = class_end;
552 parse_state.trim_left_checked( );
553 parse_state.set_class_position( old_class_pos );
557 template<
typename JsonClass,
typename ParseState>
558 [[nodiscard]]
static constexpr json_result_t<JsonClass>
559 construct_class( ParseState &parse_state, empty_locations
const & ) {
560 using result_t = json_result_t<JsonClass>;
561 using constructor_t = json_constructor_t<JsonClass>;
567 return construct_value_tp<result_t, constructor_t>( parse_state,
573 template<
typename Locations>
574 struct simd_class_value_state {
575 char const *first =
nullptr;
576 char const *last =
nullptr;
580 template<
typename JsonMember,
typename CharT,
auto... PolicyFlags>
581 class json_simd_block_iterator_class {
582 static_assert( JsonMember::underlying_json_type ==
583 JsonBaseParseTypes::Class );
585 std::is_same_v<CharT, char>,
586 "SIMD class iteration currently supports char input only" );
589 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
591 simd_class_parser<typename JsonMember::json_member_list>;
592 using locations_type =
593 typename parser_type::template locations_type<ParseState>;
594 using value_state_type = simd_class_value_state<locations_type>;
597 using json_member = JsonMember;
598 using value_type =
typename json_member::parse_to_t;
599 using reference = value_type;
600 using difference_type = std::ptrdiff_t;
601 using iterator_category = std::input_iterator_tag;
604 char const *m_first =
nullptr;
605 char const *m_last =
nullptr;
606 bool m_previous_value =
false;
607 simd_class_structural_state m_structural_state{ };
608 value_state_type m_current{
611 parser_type::template make_locations<ParseState>( ) };
613 constexpr void move_to_next_value( ) {
614 m_current.first =
nullptr;
615 m_current.last =
nullptr;
616 if( m_first ==
nullptr or m_first == m_last ) {
620 auto parse_state = ParseState( m_first, m_last );
621 parse_state.trim_left( );
622 if( parse_state.empty( ) ) {
627 if( m_previous_value ) {
628 if( parse_state.front( ) ==
']' ) {
629 parse_state.remove_prefix( );
634 ErrorReason::InvalidEndOfValue,
636 parse_state.remove_prefix( );
637 parse_state.trim_left( );
639 parse_state.front( ) !=
']',
640 ErrorReason::TrailingComma,
642 }
else if( parse_state.front( ) ==
']' ) {
643 parse_state.remove_prefix( );
649 ErrorReason::InvalidClassStart,
651 m_current.first = parse_state.data( );
652 m_current.locations =
653 parser_type::template make_locations<ParseState>( );
654 m_current.last = parser_type::template scan_class<JsonMember>(
655 parse_state, m_current.locations, m_structural_state );
656 m_first = parse_state.data( );
657 m_previous_value =
true;
661 constexpr json_simd_block_iterator_class( ) =
default;
663 explicit constexpr json_simd_block_iterator_class(
664 std::string_view document )
665 : m_first( document.data( ) )
666 , m_last(
std::next( document.data( ), static_cast<
std::ptrdiff_t>(
667 document.size( ) ) ) ) {
668 if( m_first != m_last ) {
669 auto parse_state = ParseState( m_first, m_last );
670 parse_state.trim_left( );
672 ErrorReason::InvalidArrayStart,
674 parse_state.remove_prefix( );
675 m_first = parse_state.data( );
676 m_structural_state.reset( m_first, m_last );
678 move_to_next_value( );
681 explicit constexpr json_simd_block_iterator_class(
682 std::string_view document, daw::string_view start_path )
683 : json_simd_block_iterator_class(
684 find_array_range<ParseState>( document, start_path ) ) {}
686 [[nodiscard]]
constexpr reference operator*( )
const {
687 auto parse_state = ParseState( m_current.first, m_current.last );
688 parse_state.first = m_current.last;
689 return parser_type::template construct_class<json_member>(
690 parse_state, m_current.locations );
693 constexpr json_simd_block_iterator_class &operator++( ) {
694 move_to_next_value( );
698 constexpr void operator++(
int ) {
702 [[nodiscard]]
constexpr explicit operator bool( ) const noexcept {
703 return m_current.first !=
nullptr;
706 [[nodiscard]]
constexpr json_simd_block_iterator_class begin( )
const {
710 [[nodiscard]]
constexpr json_simd_block_iterator_class
static end( ) noexcept {
714 friend constexpr bool
715 operator==( json_simd_block_iterator_class
const &lhs,
716 json_simd_block_iterator_class
const &rhs )
noexcept {
717 auto const lhs_at_end = not lhs;
718 auto const rhs_at_end = not rhs;
719 if( lhs_at_end or rhs_at_end ) {
720 return lhs_at_end == rhs_at_end;
722 return lhs.m_current.first == rhs.m_current.first;
725 friend constexpr bool
726 operator!=( json_simd_block_iterator_class
const &lhs,
727 json_simd_block_iterator_class
const &rhs )
noexcept {
728 return not( lhs == rhs );
#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.
DAW_ATTRIB_NOINLINE void daw_json_error(bool b, ErrorReason reason)
BasicParsePolicy() -> BasicParsePolicy<>
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
constexpr bool should_construct_explicitly_v
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.