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<0>( name );
217 if constexpr( must_exist ) {
219 ErrorReason::UnknownMember,
222 auto const colon = structural_state.next( name_last + 1 );
224 ErrorReason::InvalidMemberName,
226 auto value_state = ParseState( colon + 1, class_last );
227 value_state.trim_left( );
228 auto const value_first = value_state.data( );
230 ErrorReason::UnexpectedEndOfData,
233 auto object_depth = std::size_t{ 1 };
234 auto array_depth = std::size_t{ 0 };
235 auto container_count = std::size_t{ 0 };
236 char const *first_escape =
nullptr;
237 char const *string_last =
nullptr;
238 char const *decimal_point =
nullptr;
239 char const *exponent_marker =
nullptr;
240 auto const value_is_string = *value_first ==
'"';
241 auto const value_is_array = *value_first ==
'[';
242 auto const value_is_class = *value_first ==
'{';
243 auto const value_is_number =
244 *value_first ==
'-' or
245 ( *value_first >=
'0' and *value_first <=
'9' );
246 auto delimiter = structural_state.next( colon + 1 );
247 auto found_delimiter =
false;
248 while( value_is_number and delimiter !=
nullptr and
249 not found_delimiter ) {
250 switch( *delimiter ) {
252 if( decimal_point ==
nullptr ) {
253 decimal_point = delimiter;
258 if( exponent_marker ==
nullptr ) {
259 exponent_marker = delimiter;
263 found_delimiter =
true;
266 if( not found_delimiter ) {
267 delimiter = structural_state.next( delimiter + 1 );
270 while( not value_is_number and delimiter !=
nullptr and
271 not found_delimiter ) {
272 switch( *delimiter ) {
274 if( value_is_string and delimiter != value_first and
275 string_last ==
nullptr ) {
276 string_last = delimiter;
280 if( value_is_string and first_escape ==
nullptr ) {
281 first_escape = delimiter;
288 if( object_depth == 1U and array_depth == 0U ) {
289 found_delimiter =
true;
293 ErrorReason::InvalidBracketing,
302 ErrorReason::InvalidBracketing,
307 if( ( value_is_array and object_depth == 1U and
308 array_depth == 1U ) or
309 ( value_is_class and object_depth == 2U and
310 array_depth == 0U ) ) {
313 if( object_depth == 1U and array_depth == 0U ) {
314 found_delimiter =
true;
320 if( not found_delimiter ) {
321 delimiter = structural_state.next( delimiter + 1 );
326 ErrorReason::UnexpectedEndOfData,
328 auto const value_last =
329 trim_value_right( value_first, delimiter );
331 ErrorReason::InvalidStartOfValue,
333 if constexpr( not ParseState::is_unchecked_input ) {
334 switch( *value_first ) {
337 matches_literal( value_first, value_last,
"true" ),
338 ErrorReason::InvalidTrue,
343 matches_literal( value_first, value_last,
"false" ),
344 ErrorReason::InvalidFalse,
349 matches_literal( value_first, value_last,
"null" ),
350 ErrorReason::InvalidNull,
358 if( name_pos < locations.size( ) and
359 locations[name_pos].missing( ) ) {
360 auto location_state = ParseState(
361 value_first, value_last, class_first, class_last );
362 switch( *value_first ) {
365 string_last + 1 == value_last,
366 ErrorReason::InvalidString,
368 location_state.first = value_first + 1;
369 location_state.last = string_last;
370 location_state.counter =
371 first_escape ==
nullptr
372 ?
static_cast<std::size_t
>( -1 )
373 : static_cast<
std::size_t>( first_escape - ( value_first + 1 ) );
376 location_state.counter = 1U;
379 location_state.counter = 0U;
382 location_state.first =
nullptr;
383 location_state.last =
nullptr;
387 location_state.counter = container_count;
390 location_state.class_first = decimal_point;
391 location_state.class_last = exponent_marker;
394 locations[name_pos].set_range( location_state );
395 }
else if constexpr( must_exist ) {
399 after_comma = *delimiter ==
',';
401 ? structural_state.next( delimiter + 1 )
406 ErrorReason::UnexpectedEndOfData,
409 ErrorReason::TrailingComma,
412 ErrorReason::InvalidEndOfValue,
414 auto const class_end =
event + 1;
415 parse_state.first = class_end;
416 parse_state.trim_left_checked( );
417 parse_state.set_class_position( old_class_pos );
422 template<
typename JsonMember,
typename ParseState,
typename Location>
423 [[nodiscard]]
static constexpr json_result_t<JsonMember>
424 parse_member( ParseState &parse_state, Location
const &location ) {
425 auto member_state = [&] {
426 if constexpr( ParseState::has_allocator ) {
427 return location.template get_range<ParseState>( ).with_allocator(
430 return location.template get_range<ParseState>( );
433 if( member_state.is_null( ) ) {
436 return parse_class_member_impl<JsonMember, false>(
437 parse_state, find_result<ParseState>{ member_state,
true } );
439 return parse_value<without_name<JsonMember>,
441 JsonMember::expected_type>( member_state );
444 template<
typename JsonClass,
typename ParseState, std::size_t... Is>
445 [[nodiscard]]
static constexpr json_result_t<JsonClass>
446 construct_class_impl( ParseState &parse_state,
447 locations_type<ParseState>
const &locations,
448 std::index_sequence<Is...> ) {
449 using result_t = json_result_t<JsonClass>;
450 using constructor_t = json_constructor_t<JsonClass>;
455 parse_member<JsonMembers>( parse_state, locations[Is] )... };
457 return construct_value_tp<result_t, constructor_t>(
460 parse_member<JsonMembers>( parse_state, locations[Is] )... } );
465 template<
typename JsonClass,
typename ParseState>
466 [[nodiscard]]
static constexpr json_result_t<JsonClass>
467 construct_class( ParseState &parse_state,
468 locations_type<ParseState>
const &locations ) {
469 return construct_class_impl<JsonClass>(
472 std::index_sequence_for<JsonMembers...>{ } );
477 struct simd_class_parser<json_member_list<>> {
478 struct empty_locations {};
480 template<
typename ParseState>
481 using locations_type = empty_locations;
483 template<
typename ParseState>
484 [[nodiscard]]
static constexpr locations_type<ParseState>
489 template<
typename JsonClass,
typename ParseState>
490 [[nodiscard]]
static DAW_JSON_SIMD_CONSTEXPR
char const *
491 scan_class( ParseState &parse_state, empty_locations &,
492 simd_class_structural_state &structural_state ) {
493 using result_t = json_result_t<JsonClass>;
494 parse_state.trim_left( );
496 ErrorReason::InvalidClassStart,
498 auto const old_class_pos = parse_state.get_class_position( );
499 auto const class_first = parse_state.data( );
500 parse_state.set_class_position( );
501 auto event = structural_state.next( class_first );
503 ErrorReason::InvalidClassStart,
505 event = structural_state.next( event + 1 );
506 if constexpr( all_json_members_must_exist_v<result_t, ParseState> ) {
508 ErrorReason::UnknownMember,
511 auto object_depth = std::size_t{ 1 };
512 auto array_depth = std::size_t{ 0 };
513 auto found_end =
false;
514 while( event !=
nullptr and not found_end ) {
520 if( object_depth == 1U and array_depth == 0U ) {
525 ErrorReason::InvalidBracketing,
534 ErrorReason::InvalidBracketing,
541 if( not found_end ) {
542 event = structural_state.next( event + 1 );
546 ErrorReason::UnexpectedEndOfData,
549 auto const class_end =
event + 1;
550 parse_state.first = class_end;
551 parse_state.trim_left_checked( );
552 parse_state.set_class_position( old_class_pos );
556 template<
typename JsonClass,
typename ParseState>
557 [[nodiscard]]
static constexpr json_result_t<JsonClass>
558 construct_class( ParseState &parse_state, empty_locations
const & ) {
559 using result_t = json_result_t<JsonClass>;
560 using constructor_t = json_constructor_t<JsonClass>;
566 return construct_value_tp<result_t, constructor_t>( parse_state,
572 template<
typename Locations>
573 struct simd_class_value_state {
574 char const *first =
nullptr;
575 char const *last =
nullptr;
579 template<
typename JsonMember,
typename CharT,
auto... PolicyFlags>
580 class json_simd_block_iterator_class {
581 static_assert( JsonMember::underlying_json_type ==
582 JsonBaseParseTypes::Class );
584 std::is_same_v<CharT, char>,
585 "SIMD class iteration currently supports char input only" );
588 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
590 simd_class_parser<typename JsonMember::json_member_list>;
591 using locations_type =
592 typename parser_type::template locations_type<ParseState>;
593 using value_state_type = simd_class_value_state<locations_type>;
596 using json_member = JsonMember;
597 using value_type =
typename json_member::parse_to_t;
598 using reference = value_type;
599 using difference_type = std::ptrdiff_t;
600 using iterator_category = std::input_iterator_tag;
603 char const *m_first =
nullptr;
604 char const *m_last =
nullptr;
605 bool m_previous_value =
false;
606 simd_class_structural_state m_structural_state{ };
607 value_state_type m_current{
610 parser_type::template make_locations<ParseState>( ) };
612 constexpr void move_to_next_value( ) {
613 m_current.first =
nullptr;
614 m_current.last =
nullptr;
615 if( m_first ==
nullptr or m_first == m_last ) {
619 auto parse_state = ParseState( m_first, m_last );
620 parse_state.trim_left( );
621 if( parse_state.empty( ) ) {
626 if( m_previous_value ) {
627 if( parse_state.front( ) ==
']' ) {
628 parse_state.remove_prefix( );
633 ErrorReason::InvalidEndOfValue,
635 parse_state.remove_prefix( );
636 parse_state.trim_left( );
638 parse_state.front( ) !=
']',
639 ErrorReason::TrailingComma,
641 }
else if( parse_state.front( ) ==
']' ) {
642 parse_state.remove_prefix( );
648 ErrorReason::InvalidClassStart,
650 m_current.first = parse_state.data( );
651 m_current.locations =
652 parser_type::template make_locations<ParseState>( );
653 m_current.last = parser_type::template scan_class<JsonMember>(
654 parse_state, m_current.locations, m_structural_state );
655 m_first = parse_state.data( );
656 m_previous_value =
true;
660 constexpr json_simd_block_iterator_class( ) =
default;
662 explicit constexpr json_simd_block_iterator_class(
663 std::string_view document )
664 : m_first( document.data( ) )
665 , m_last(
std::next( document.data( ), static_cast<
std::ptrdiff_t>(
666 document.size( ) ) ) ) {
667 if( m_first != m_last ) {
668 auto parse_state = ParseState( m_first, m_last );
669 parse_state.trim_left( );
671 ErrorReason::InvalidArrayStart,
673 parse_state.remove_prefix( );
674 m_first = parse_state.data( );
675 m_structural_state.reset( m_first, m_last );
677 move_to_next_value( );
680 explicit constexpr json_simd_block_iterator_class(
681 std::string_view document, daw::string_view start_path )
682 : json_simd_block_iterator_class(
683 find_array_range<ParseState>( document, start_path ) ) {}
685 [[nodiscard]]
constexpr reference operator*( )
const {
686 auto parse_state = ParseState( m_current.first, m_current.last );
687 parse_state.first = m_current.last;
688 return parser_type::template construct_class<json_member>(
689 parse_state, m_current.locations );
692 constexpr json_simd_block_iterator_class &operator++( ) {
693 move_to_next_value( );
697 constexpr void operator++(
int ) {
701 [[nodiscard]]
constexpr explicit operator bool( ) const noexcept {
702 return m_current.first !=
nullptr;
705 [[nodiscard]]
constexpr json_simd_block_iterator_class begin( )
const {
709 [[nodiscard]]
constexpr json_simd_block_iterator_class
static end( ) noexcept {
713 friend constexpr bool
714 operator==( json_simd_block_iterator_class
const &lhs,
715 json_simd_block_iterator_class
const &rhs )
noexcept {
716 auto const lhs_at_end = not lhs;
717 auto const rhs_at_end = not rhs;
718 if( lhs_at_end or rhs_at_end ) {
719 return lhs_at_end == rhs_at_end;
721 return lhs.m_current.first == rhs.m_current.first;
724 friend constexpr bool
725 operator!=( json_simd_block_iterator_class
const &lhs,
726 json_simd_block_iterator_class
const &rhs )
noexcept {
727 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
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.