DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd_iterator_bool.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_bool {
20 static_assert( JsonMember::underlying_json_type ==
21 JsonBaseParseTypes::Bool );
22 using ParseState = TryDefaultParsePolicy<BasicParsePolicy<
23 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
24 using classifier_type =
25 simd_json_classifier<JsonBaseParseTypes::Bool, CharT>;
26 using block_type = simd_json_block<JsonBaseParseTypes::Bool, CharT>;
27
28 public:
29 using json_member = JsonMember;
30 using value_type = typename json_member::parse_to_t;
31 using reference = value_type;
32 using difference_type = std::ptrdiff_t;
33 using iterator_category = std::input_iterator_tag;
34
35 private:
36 static constexpr std::size_t boolean_cache_words = 4U;
37 static constexpr std::size_t boolean_cache_capacity =
38 boolean_cache_words * 64U;
39
40 char const *m_first = nullptr;
41 char const *m_last = nullptr;
42 std::array<std::uint64_t, boolean_cache_words> m_boolean_values{ };
43 std::size_t m_value_index = 0;
44 std::size_t m_value_count = 0;
45 simd_json_classifier_state m_state{ };
46 simd_array_grammar_state m_grammar_state{ };
47
48 constexpr void append_boolean_values( std::uint64_t values,
49 std::size_t count ) {
50 auto const word = m_value_count / 64U;
51 auto const shift = m_value_count % 64U;
52 m_boolean_values[word] |= values << shift;
53 if( shift != 0U and shift + count > 64U ) {
54 m_boolean_values[word + 1U] = values >> ( 64U - shift );
55 }
56 m_value_count += count;
57 }
58
59 constexpr void validate_boolean( char const *first, bool value ) const {
60 if constexpr( not ParseState::is_unchecked_input ) {
61 auto parse_state = ParseState( first, m_last );
62 if( value ) {
63 daw_json_assert_weak( parse_state.starts_with( "true" ),
64 ErrorReason::InvalidLiteral,
65 parse_state );
66 parse_state.remove_prefix( 4 );
67 } else {
68 daw_json_assert_weak( parse_state.starts_with( "false" ),
69 ErrorReason::InvalidLiteral,
70 parse_state );
71 parse_state.remove_prefix( 5 );
72 }
73 parse_state.trim_left( );
75 not parse_state.has_more( ) or
76 parse_policy_details::at_end_of_item( parse_state.front( ) ),
77 ErrorReason::InvalidEndOfValue,
78 parse_state );
79 }
80 }
81
82 constexpr void fill_buffer( ) {
83 m_boolean_values = { };
84 m_value_index = 0;
85 m_value_count = 0;
86
87 // Reserving a full classifier block means a classified block is never
88 // partially consumed. In particular, the classifier and grammar
89 // state always describe exactly the position held in m_first.
90 while( m_first != nullptr and m_first != m_last and
91 m_value_count + block_type::block_size <=
92 boolean_cache_capacity ) {
93 auto const remaining = static_cast<std::size_t>( m_last - m_first );
94 auto const block = classifier_type::template classify_bool<
95 not ParseState::is_unchecked_input>(
96 m_first, remaining, m_state );
97 if constexpr( not ParseState::is_unchecked_input ) {
98 auto const unexpected_starts =
99 block.scalar_start & ~block.boolean_start;
100 if( unexpected_starts != 0 ) {
101 auto const lane = static_cast<std::size_t>(
102 daw::cxmath::count_trailing_zeros( unexpected_starts ) );
103 auto error_state = ParseState( block.data + lane, m_last );
105 true, ErrorReason::InvalidLiteral, error_state );
106 }
107 validate_array_events<ParseState>( block.data,
108 m_last,
109 block.boolean_start,
110 block.comma,
111 block.array_end,
112 m_grammar_state );
113 }
114
115 auto const starts = block.boolean_start;
116 auto const block_value_count =
117 static_cast<std::size_t>( daw::cxmath::popcount( starts ) );
118
119 if constexpr( not ParseState::is_unchecked_input ) {
120 auto validation_starts = starts;
121 auto values = block.boolean_values;
122 for( std::size_t n = 0; n < block_value_count; ++n ) {
123 auto const lane = static_cast<std::size_t>(
124 daw::cxmath::count_trailing_zeros( validation_starts ) );
125 validate_boolean( block.data + lane,
126 ( values & std::uint64_t{ 1 } ) != 0 );
127 validation_starts &= validation_starts - 1U;
128 values >>= 1U;
129 }
130 }
131
132 append_boolean_values( block.boolean_values, block_value_count );
133 if( block.array_end != 0 ) {
134 m_first = m_last;
135 } else {
136 m_first += static_cast<std::ptrdiff_t>( block.size );
137 }
138 }
139 if constexpr( not ParseState::is_unchecked_input ) {
140 if( m_first != nullptr and m_first == m_last ) {
141 validate_array_ended<ParseState>( m_last, m_grammar_state );
142 }
143 }
144 }
145
146 public:
147 constexpr json_simd_block_iterator_bool( ) = default;
148
149 explicit constexpr json_simd_block_iterator_bool(
150 std::string_view document )
151 : m_first( document.data( ) )
152 , m_last( std::next( document.data( ), static_cast<std::ptrdiff_t>(
153 document.size( ) ) ) ) {
154 if( m_first != m_last ) {
155 auto parse_state = ParseState( m_first, m_last );
156 parse_state.trim_left( );
157 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
158 ErrorReason::InvalidArrayStart,
159 parse_state );
160 parse_state.remove_prefix( );
161 m_first = parse_state.data( );
162 m_grammar_state.started = true;
163 }
164 fill_buffer( );
165 }
166
167 explicit constexpr json_simd_block_iterator_bool(
168 std::string_view document, daw::string_view start_path )
169 : json_simd_block_iterator_bool(
170 find_array_range<ParseState>( document, start_path ) ) {}
171
172 [[nodiscard]] constexpr reference operator*( ) const {
173 static_assert(
174 json_member::literal_as_string ==
175 options::LiteralAsStringOpt::Never,
176 "SIMD boolean iteration does not support literals encoded as "
177 "strings" );
178 auto const word = m_value_index / 64U;
179 auto const shift = m_value_index % 64U;
180 auto const value =
181 ( ( m_boolean_values[word] >> shift ) & std::uint64_t{ 1 } ) != 0;
182 using constructor_t = json_constructor_t<json_member>;
183 static_assert(
184 daw::is_callable_v<constructor_t, bool>,
185 "Unable to construct value with the supplied arguments" );
186 return constructor_t{ }( value );
187 }
188
189 constexpr json_simd_block_iterator_bool &operator++( ) {
190 if( m_value_index < m_value_count ) {
191 ++m_value_index;
192 }
193 if( m_value_index == m_value_count ) {
194 fill_buffer( );
195 }
196 return *this;
197 }
198
199 constexpr void operator++( int ) {
200 (void)operator++( );
201 }
202
203 [[nodiscard]] constexpr explicit operator bool( ) const noexcept {
204 return m_value_index < m_value_count;
205 }
206
207 [[nodiscard]] constexpr json_simd_block_iterator_bool begin( ) const {
208 return *this;
209 }
210
211 [[nodiscard]] constexpr json_simd_block_iterator_bool static end( ) noexcept {
212 return { };
213 }
214
215 friend constexpr bool
216 operator==( json_simd_block_iterator_bool const &lhs,
217 json_simd_block_iterator_bool const &rhs ) noexcept {
218 auto const lhs_at_end = not lhs;
219 auto const rhs_at_end = not rhs;
220 if( lhs_at_end or rhs_at_end ) {
221 return lhs_at_end == rhs_at_end;
222 }
223 return lhs.m_first == rhs.m_first and
224 lhs.m_value_index == rhs.m_value_index and
225 lhs.m_value_count == rhs.m_value_count;
226 }
227
228 friend constexpr bool
229 operator!=( json_simd_block_iterator_bool const &lhs,
230 json_simd_block_iterator_bool const &rhs ) noexcept {
231 return not( lhs == rhs );
232 }
233 };
234 } // namespace json_details::simd_details
235 } // namespace DAW_JSON_VER
236} // namespace daw::json
237
238#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