DAW JSON Link
Loading...
Searching...
No Matches
daw_json_parse_policy_no_comments.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
18
19#include <daw/daw_attributes.h>
20#include <daw/daw_constant.h>
21#include <daw/daw_function_table.h>
22#include <daw/daw_likely.h>
23#include <daw/daw_not_null.h>
24#include <daw/daw_traits.h>
25
26#include <cstddef>
27#include <cstdint>
28#include <type_traits>
29
30namespace daw::json {
31 inline namespace DAW_JSON_VER {
33 template<typename ParseState>
34 DAW_ATTRIB_FLATINLINE static constexpr void
35 trim_left_checked( ParseState &parse_state ) {
36 if constexpr( not ParseState::minified_document ) {
37 // SIMD here was much slower, most JSON has very minimal whitespace
38 auto first =
39 daw::not_null<typename ParseState::iterator>( parse_state.first );
40 auto const last = daw::not_null<char const *>( parse_state.last );
41
42 // only used when not zero terminated string and gcc9 warns
43 (void)last;
44
45 if constexpr( ParseState::is_zero_terminated_string ) {
46 // Ensure that zero terminator isn't included in skipable value
47 while( DAW_UNLIKELY(
48 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
49 1U ) <= 0x1FU ) ) {
50
51 ++first;
52 }
53 } else {
54 while(
55 DAW_LIKELY( first < last ) and
56 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
57 1U ) <= 0x1FU ) {
58 ++first;
59 }
60 }
61 parse_state.first = json_details::input_pointer( parse_state.first, first.get( ) );
62 }
63 }
64
65 template<typename ParseState>
66 DAW_ATTRIB_FLATINLINE static constexpr void
67 trim_left_unchecked( ParseState &parse_state ) {
68 if constexpr( not ParseState::minified_document ) {
69 auto first = daw::not_null<typename ParseState::iterator>(
70 daw::never_null, parse_state.first );
71 while( DAW_UNLIKELY(
72 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
73 1U ) <= 0x1F ) ) {
74
75 ++first;
76 }
77 parse_state.first = json_details::input_pointer( parse_state.first, first.get( ) );
78 }
79 }
80
81 template<typename ParseState>
82 DAW_ATTRIB_FLATINLINE static constexpr void
83 move_next_member_unchecked( ParseState &parse_state ) {
84 auto pf = daw::not_null<char const *>( daw::never_null, parse_state.first );
85 auto pl = daw::not_null<char const *>( daw::never_null, parse_state.last );
86 auto const position =
87 json_details::memchr_unchecked<'"',
88 typename ParseState::exec_tag_t,
89 ParseState::expect_long_strings>( pf,
90 pl );
91 parse_state.first = json_details::input_pointer( parse_state.first, position.get( ) );
92 }
93
94 template<char... keys, typename ParseState>
95 DAW_ATTRIB_FLATINLINE static constexpr void
96 move_to_next_of( ParseState &parse_state ) {
97 static_assert( sizeof...( keys ) > 0 );
98 static_assert( sizeof...( keys ) <= 16 );
99
100 if( not json_details::use_constexpr_exec_mode<
101 typename ParseState::exec_tag_t>( ) ) {
102 auto pf = daw::not_null<char const *>{ parse_state.first };
103 auto pl = daw::not_null<char const *>{ parse_state.last };
104 auto const position =
105 json_details::mempbrk<ParseState::is_unchecked_input,
106 typename ParseState::exec_tag_t,
107 ParseState::expect_long_strings,
108 keys...>( pf, pl );
109 parse_state.first = json_details::input_pointer( parse_state.first, position.get( ) );
110 } else {
111 auto first = daw::not_null<char const *>( parse_state.first );
112 auto const last = daw::not_null<char const *>( parse_state.last );
113
114 // silencing gcc9 unused warning. last is used inside if constexpr
115 // blocks
116 (void)last;
117
118 if( ParseState::is_zero_terminated_string ) {
119 daw_json_assert_weak( first < last and *first != '\0',
120 ErrorReason::UnexpectedEndOfData,
121 parse_state );
122 while( not parse_policy_details::in<keys...>( *first ) ) {
123 ++first;
124 }
126 *first != '\0', ErrorReason::UnexpectedEndOfData, parse_state );
127 } else {
129 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
130 while( not parse_policy_details::in<keys...>( *first ) ) {
131 ++first;
133 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
134 }
135 }
136 parse_state.first = json_details::input_pointer( parse_state.first, first.get( ) );
137 }
138 }
139
140 DAW_ATTRIB_INLINE static constexpr bool is_literal_end( char c ) {
141 return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
142 }
143
144 template<json_details::SkipBracketedType BracketedType,
145 typename ParseState>
146 DAW_ATTRIB_FLATTEN static constexpr ParseState
147 skip_bracketed_item_checked( ParseState &parse_state ) {
148 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
149 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
150 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
151 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
152 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
153
154 // Not checking for Left as it is required to be skipped already
155 auto ptr_first = daw::not_null<char const *>( parse_state.first );
156 auto const ptr_last = daw::not_null<char const *>( parse_state.last );
157 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
158 return parse_state;
159 }
160 auto result = parse_state;
161 std::size_t cnt = 0;
162 std::uint32_t prime_bracket_count = 1;
163 std::uint32_t second_bracket_count = 0;
164
165 if( *ptr_first == PrimLeft ) {
166 ++ptr_first;
167 }
168 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
169 switch( *ptr_first ) {
170 case '\\':
171 ++ptr_first;
172 break;
173 case '"':
174 ++ptr_first;
175 ptr_first = json_details::mem_skip_until_end_of_string<
176 ParseState::is_unchecked_input,
177 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
178 daw_json_ensure( ptr_first < ptr_last and *ptr_first == '"',
179 ErrorReason::UnexpectedEndOfData,
180 parse_state );
181 break;
182 case ',':
183 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
184 ( second_bracket_count == 0 ) ) ) {
185 ++cnt;
186 }
187 break;
188 case PrimLeft:
189 ++prime_bracket_count;
190 break;
191 case PrimRight::value:
192 --prime_bracket_count;
193 if( prime_bracket_count == 0 ) {
194 ++ptr_first;
195 daw_json_ensure( second_bracket_count == 0,
196 ErrorReason::InvalidBracketing,
197 parse_state );
198 result.last = json_details::input_pointer( result.first, ptr_first.get( ) );
199 result.counter = cnt;
200 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first.get( ) );
201 return result;
202 }
203 break;
204 case SecLeft::value:
205 ++second_bracket_count;
206 break;
207 case SecRight::value:
208 --second_bracket_count;
209 break;
210 }
211 ++ptr_first;
212 }
213 daw_json_ensure( ( prime_bracket_count == 0 ) &
214 ( second_bracket_count == 0 ),
215 ErrorReason::InvalidBracketing,
216 parse_state );
217 // We include the close primary bracket in the range so that subsequent
218 // parsers have a terminator inside their range
219 result.last = json_details::input_pointer( result.first, ptr_first.get( ) );
220 result.counter = cnt;
221 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first.get( ) );
222 return result;
223 }
224
225 template<json_details::SkipBracketedType BracketedType,
226 typename ParseState>
227 DAW_ATTRIB_NOINLINE static constexpr ParseState
228 skip_bracketed_item_unchecked( ParseState &parse_state ) {
229 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
230 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
231 // Not checking for Left as it is required to be skipped already
232 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
233 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
234 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
235
236 auto result = parse_state;
237 std::size_t cnt = 0;
238 std::uint32_t prime_bracket_count = 1;
239 std::uint32_t second_bracket_count = 0;
240 auto ptr_first = daw::not_null<char const *>( parse_state.first );
241 auto const ptr_last = daw::not_null<char const *>( parse_state.last );
242
243 if( *ptr_first == PrimLeft ) {
244 ++ptr_first;
245 }
246 while( true ) {
247 switch( *ptr_first ) {
248 case '\\':
249 ++ptr_first;
250 break;
251 case '"':
252 ++ptr_first;
253 ptr_first = json_details::mem_skip_until_end_of_string<
254 ParseState::is_unchecked_input,
255 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
256 break;
257 case ',':
258 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
259 ( second_bracket_count == 0 ) ) ) {
260 ++cnt;
261 }
262 break;
263 case PrimLeft:
264 ++prime_bracket_count;
265 break;
266 case PrimRight::value:
267 --prime_bracket_count;
268 if( prime_bracket_count == 0 ) {
269 ++ptr_first;
270 // We include the close primary bracket in the range so that
271 // subsequent parsers have a terminator inside their range
272 result.last = json_details::input_pointer( result.first, ptr_first.get( ) );
273 result.counter = cnt;
274 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first.get( ) );
275 return result;
276 }
277 break;
278 case SecLeft::value:
279 ++second_bracket_count;
280 break;
281 case SecRight::value:
282 --second_bracket_count;
283 break;
284 }
285 ++ptr_first;
286 }
287 // Should never get here, only loop exit is when PrimaryRight is found
288 // and count == 0
289 DAW_UNREACHABLE( );
290 }
291 };
292 } // namespace DAW_JSON_VER
293} // namespace daw::json
#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.
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
Customization point traits.
static DAW_ATTRIB_NOINLINE constexpr ParseState skip_bracketed_item_unchecked(ParseState &parse_state)
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20