DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd_iterator_string.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
13#if defined( DAW_JSON_HAS_SIMD )
14
15namespace daw::json {
16 inline namespace DAW_JSON_VER {
17 namespace json_details::simd_details {
18 template<typename JsonMember, typename CharT, auto... PolicyFlags>
19 class json_simd_block_iterator_string {
20 static_assert( JsonMember::underlying_json_type ==
21 JsonBaseParseTypes::String );
22 using ParseState = TryDefaultParsePolicy<BasicParsePolicy<
23 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
24 using classifier_type =
25 simd_json_classifier<JsonBaseParseTypes::String, CharT>;
26
27 public:
28 using json_member = JsonMember;
29 using value_type = typename json_member::parse_to_t;
30 using reference = value_type;
31 using difference_type = std::ptrdiff_t;
32 using iterator_category = std::input_iterator_tag;
33
34 private:
35 char const *m_first = nullptr;
36 char const *m_last = nullptr;
37 char const *m_current = nullptr;
38 char const *m_current_end = nullptr;
39 char const *m_current_escape = nullptr;
40 char const *m_block_data = nullptr;
41 std::uint64_t m_value_starts = 0;
42 std::uint64_t m_string_ends = 0;
43 std::uint64_t m_escape_characters = 0;
44 simd_json_classifier_state m_state{ };
45 simd_array_grammar_state m_grammar_state{ };
46
47 [[nodiscard]] constexpr bool classify_next_block( ) {
48 if( m_first == nullptr or m_first == m_last ) {
49 if constexpr( not ParseState::is_unchecked_input ) {
50 if( m_first != nullptr ) {
51 validate_array_ended<ParseState>( m_last, m_grammar_state );
52 }
53 }
54 return false;
55 }
56
57 auto const remaining = static_cast<std::size_t>( m_last - m_first );
58 auto const block = classifier_type::template classify_string<
59 not ParseState::is_unchecked_input>( m_first, remaining, m_state );
60 m_block_data = block.data;
61 m_value_starts = block.string_start;
62 m_string_ends = block.string_end;
63 m_escape_characters = block.escape_characters;
64 if constexpr( not ParseState::is_unchecked_input ) {
65 auto const unexpected_starts = block.scalar_start & ~m_value_starts;
66 if( unexpected_starts != 0 ) {
67 auto const lane = static_cast<std::size_t>(
68 daw::cxmath::count_trailing_zeros( unexpected_starts ) );
69 auto error_state = ParseState( block.data + lane, m_last );
70 daw_json_error( true, ErrorReason::InvalidString, error_state );
71 }
72 validate_array_events<ParseState>( block.data,
73 m_last,
74 block.string_start,
75 block.comma,
76 block.array_end,
77 m_grammar_state );
78 }
79 if( block.array_end != 0 ) {
80 m_first = m_last;
81 } else {
82 m_first += static_cast<std::ptrdiff_t>( block.size );
83 }
84 return true;
85 }
86
87 constexpr void move_to_next_value( ) {
88 while( m_value_starts == 0 ) {
89 if( not classify_next_block( ) ) {
90 m_current = nullptr;
91 m_current_end = nullptr;
92 m_current_escape = nullptr;
93 return;
94 }
95 }
96
97 auto const lane = static_cast<std::size_t>(
98 daw::cxmath::count_trailing_zeros( m_value_starts ) );
99 m_value_starts &= m_value_starts - 1U;
100 m_current = m_block_data + lane;
101 m_current_escape = nullptr;
102
103 auto first_lane = lane + 1U;
104 while( true ) {
105 if( m_string_ends != 0 ) {
106 auto const end_lane = static_cast<std::size_t>(
107 daw::cxmath::count_trailing_zeros( m_string_ends ) );
108 auto const escapes = m_escape_characters &
109 simd_details::low_bits( end_lane ) &
110 ~simd_details::low_bits( first_lane );
111 if( m_current_escape == nullptr and escapes != 0 ) {
112 m_current_escape =
113 m_block_data + daw::cxmath::count_trailing_zeros( escapes );
114 }
115 m_string_ends &= m_string_ends - 1U;
116 m_current_end = m_block_data + end_lane;
117 return;
118 }
119
120 auto const escapes =
121 m_escape_characters & ~simd_details::low_bits( first_lane );
122 if( m_current_escape == nullptr and escapes != 0 ) {
123 m_current_escape =
124 m_block_data + daw::cxmath::count_trailing_zeros( escapes );
125 }
126 if( not classify_next_block( ) ) {
127 auto error_state = ParseState( m_current, m_last );
128 daw_json_error( true, ErrorReason::InvalidString, error_state );
129 }
130 first_lane = 0;
131 }
132 }
133
134 public:
135 constexpr json_simd_block_iterator_string( ) = default;
136
137 explicit constexpr json_simd_block_iterator_string(
138 std::string_view document )
139 : m_first( document.data( ) )
140 , m_last( std::next( document.data( ), static_cast<std::ptrdiff_t>(
141 document.size( ) ) ) ) {
142 if( m_first != m_last ) {
143 auto parse_state = ParseState( m_first, m_last );
144 parse_state.trim_left( );
145 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
146 ErrorReason::InvalidArrayStart,
147 parse_state );
148 parse_state.remove_prefix( );
149 m_first = parse_state.data( );
150 m_grammar_state.started = true;
151 }
152 move_to_next_value( );
153 }
154
155 explicit constexpr json_simd_block_iterator_string(
156 std::string_view document, daw::string_view start_path )
157 : json_simd_block_iterator_string(
158 find_array_range<ParseState>( document, start_path ) ) {}
159
160 [[nodiscard]] constexpr reference operator*( ) const {
161 auto parse_state = ParseState( m_current + 1, m_current_end );
162 parse_state.counter = m_current_escape == nullptr
163 ? static_cast<std::size_t>( -1 )
164 : static_cast<std::size_t>(
165 m_current_escape - ( m_current + 1 ) );
166 return json_details::
167 parse_value<json_member, true, json_member::expected_type>(
168 parse_state );
169 }
170
171 constexpr json_simd_block_iterator_string &operator++( ) {
172 move_to_next_value( );
173 return *this;
174 }
175
176 constexpr void operator++( int ) {
177 (void)operator++( );
178 }
179
180 [[nodiscard]] constexpr explicit operator bool( ) const noexcept {
181 return m_current != nullptr;
182 }
183
184 [[nodiscard]] constexpr json_simd_block_iterator_string begin( ) const {
185 return *this;
186 }
187
188 [[nodiscard]] constexpr json_simd_block_iterator_string static end( ) noexcept {
189 return { };
190 }
191
192 friend constexpr bool
193 operator==( json_simd_block_iterator_string const &lhs,
194 json_simd_block_iterator_string const &rhs ) noexcept {
195 auto const lhs_at_end = lhs.m_current == nullptr;
196 auto const rhs_at_end = rhs.m_current == nullptr;
197 if( lhs_at_end or rhs_at_end ) {
198 return lhs_at_end == rhs_at_end;
199 }
200 return lhs.m_current == rhs.m_current;
201 }
202
203 friend constexpr bool
204 operator!=( json_simd_block_iterator_string const &lhs,
205 json_simd_block_iterator_string const &rhs ) noexcept {
206 return not( lhs == rhs );
207 }
208 };
209 } // namespace json_details::simd_details
210 } // namespace DAW_JSON_VER
211} // namespace daw::json
212
213#endif
#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)
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20