DAW JSON Link
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
11#include "daw_json_assert.h"
16#include "version.h"
17
18#include <daw/daw_attributes.h>
19#include <daw/daw_function_table.h>
20#include <daw/daw_likely.h>
21#include <daw/daw_traits.h>
22
23#include <ciso646>
24#include <cstddef>
25#include <cstdint>
26#include <type_traits>
27
28namespace daw::json {
29 inline namespace DAW_JSON_VER {
31 template<typename ParseState>
32 DAW_ATTRIB_FLATINLINE static constexpr void
34 if constexpr( ParseState::minified_document ) {
35 return;
36 } else {
37 using CharT = typename ParseState::CharT;
38 // SIMD here was much slower, most JSON has very minimal whitespace
39 CharT *first = parse_state.first;
40 CharT *const last = 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 = first;
62 }
63 }
64
65 template<typename ParseState>
66 DAW_ATTRIB_FLATINLINE static constexpr void
68 if constexpr( ParseState::minified_document ) {
69 return;
70 } else {
71 using CharT = typename ParseState::CharT;
72 CharT *first = parse_state.first;
73 while( DAW_UNLIKELY(
74 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
75 1U ) <= 0x1F ) ) {
76
77 ++first;
78 }
79 parse_state.first = first;
80 }
81 }
82
83 template<typename ParseState>
84 DAW_ATTRIB_FLATINLINE static constexpr void
86 parse_state.first =
87 json_details::memchr_unchecked<'"', typename ParseState::exec_tag_t,
88 ParseState::expect_long_strings>(
89 parse_state.first, parse_state.last );
90 }
91
92 template<char... keys, typename ParseState>
93 DAW_ATTRIB_FLATINLINE static constexpr void
95 static_assert( sizeof...( keys ) > 0 );
96 static_assert( sizeof...( keys ) <= 16 );
97
98 using CharT = typename ParseState::CharT;
99
100 if constexpr( traits::not_same<typename ParseState::exec_tag_t,
101 constexpr_exec_tag>::value ) {
102 parse_state.first =
103 json_details::mempbrk<ParseState::is_unchecked_input,
104 typename ParseState::exec_tag_t,
105 ParseState::expect_long_strings, keys...>(
106 parse_state.first, parse_state.last );
107 } else {
108 CharT *first = parse_state.first;
109 CharT *const last = parse_state.last;
110
111 // silencing gcc9 unused warning. last is used inside if constexpr
112 // blocks
113 (void)last;
114
115 if( ParseState::is_zero_terminated_string ) {
116 daw_json_assert_weak( first < last and *first != '\0',
117 ErrorReason::UnexpectedEndOfData,
118 parse_state );
119 while( not parse_policy_details::in<keys...>( *first ) ) {
120 ++first;
121 }
122 daw_json_assert_weak( *first != 0, ErrorReason::UnexpectedEndOfData,
123 parse_state );
124 } else {
126 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
127 while( not parse_policy_details::in<keys...>( *first ) ) {
128 ++first;
130 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
131 }
132 }
133 parse_state.first = first;
134 }
135 }
136
137 DAW_ATTRIB_INLINE static constexpr bool is_literal_end( char c ) {
138 return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
139 }
140
141 template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
142 typename ParseState>
143 DAW_ATTRIB_FLATTEN static constexpr ParseState
145 using CharT = typename ParseState::CharT;
146 // Not checking for Left as it is required to be skipped already
147 auto result = parse_state;
148 std::size_t cnt = 0;
149 std::uint32_t prime_bracket_count = 1;
150 std::uint32_t second_bracket_count = 0;
151 CharT *ptr_first = parse_state.first;
152 CharT *const ptr_last = parse_state.last;
153
154 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
155 return result;
156 }
157 if( *ptr_first == PrimLeft ) {
158 ++ptr_first;
159 }
160 if constexpr( ParseState::is_zero_terminated_string ) {
161 daw_json_assert( ptr_first < ptr_last,
162 ErrorReason::UnexpectedEndOfData, parse_state );
163 while( *ptr_first != 0 ) {
164 switch( *ptr_first ) {
165 case '\\':
166 ++ptr_first;
167 break;
168 case '"':
169 ++ptr_first;
170 if constexpr( traits::not_same<typename ParseState::exec_tag_t,
171 constexpr_exec_tag>::value ) {
173 ParseState::is_unchecked_input>(
174 ParseState::exec_tag, ptr_first, parse_state.last );
175 } else {
176 char c = *ptr_first;
177 while( ( c != '\0' ) & ( c != '"' ) ) {
178 if( c == '\\' ) {
179 if( ptr_first + 1 < ptr_last ) {
180 ptr_first += 2;
181 c = *ptr_first;
182 continue;
183 } else {
184 ptr_first = ptr_last;
185 break;
186 }
187 }
188 ++ptr_first;
189 c = *ptr_first;
190 }
191 }
192 daw_json_assert( ( *ptr_first != '\0' ) & ( *ptr_first == '"' ),
193 ErrorReason::UnexpectedEndOfData, parse_state );
194 break;
195 case ',':
196 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
197 ( second_bracket_count == 0 ) ) ) {
198 ++cnt;
199 }
200 break;
201 case PrimLeft:
202 ++prime_bracket_count;
203 break;
204 case PrimRight:
205 --prime_bracket_count;
206 if( prime_bracket_count == 0 ) {
207 ++ptr_first;
208 daw_json_assert( second_bracket_count == 0,
209 ErrorReason::InvalidBracketing, parse_state );
210 result.last = ptr_first;
211 result.counter = cnt;
212 parse_state.first = ptr_first;
213 return result;
214 }
215 break;
216 case SecLeft:
217 ++second_bracket_count;
218 break;
219 case SecRight:
220 --second_bracket_count;
221 break;
222 }
223 ++ptr_first;
224 }
225 } else {
226 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
227 switch( *ptr_first ) {
228 case '\\':
229 ++ptr_first;
230 break;
231 case '"':
232 ++ptr_first;
233 if constexpr( traits::not_same<typename ParseState::exec_tag_t,
234 constexpr_exec_tag>::value ) {
236 ParseState::is_unchecked_input>(
237 ParseState::exec_tag, ptr_first, parse_state.last );
238 } else {
239 while( DAW_LIKELY( ptr_first < ptr_last ) and
240 *ptr_first != '"' ) {
241 if( *ptr_first == '\\' ) {
242 if( ptr_first + 1 < ptr_last ) {
243 ptr_first += 2;
244 continue;
245 } else {
246 ptr_first = ptr_last;
247 break;
248 }
249 }
250 ++ptr_first;
251 }
252 }
253 daw_json_assert( ptr_first < ptr_last and *ptr_first == '"',
254 ErrorReason::UnexpectedEndOfData, parse_state );
255 break;
256 case ',':
257 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
258 ( second_bracket_count == 0 ) ) ) {
259 ++cnt;
260 }
261 break;
262 case PrimLeft:
263 ++prime_bracket_count;
264 break;
265 case PrimRight:
266 --prime_bracket_count;
267 if( prime_bracket_count == 0 ) {
268 ++ptr_first;
269 daw_json_assert( second_bracket_count == 0,
270 ErrorReason::InvalidBracketing, parse_state );
271 result.last = ptr_first;
272 result.counter = cnt;
273 parse_state.first = ptr_first;
274 return result;
275 }
276 break;
277 case SecLeft:
278 ++second_bracket_count;
279 break;
280 case SecRight:
281 --second_bracket_count;
282 break;
283 }
284 ++ptr_first;
285 }
286 }
287 daw_json_assert( ( prime_bracket_count == 0 ) &
288 ( second_bracket_count == 0 ),
289 ErrorReason::InvalidBracketing, parse_state );
290 // We include the close primary bracket in the range so that subsequent
291 // parsers have a terminator inside their range
292 result.last = ptr_first;
293 result.counter = cnt;
294 parse_state.first = ptr_first;
295 return result;
296 }
297
298 template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
299 typename ParseState>
300 DAW_ATTRIB_FLATTEN static constexpr ParseState
302 // Not checking for Left as it is required to be skipped already
303 using CharT = typename ParseState::CharT;
304 auto result = parse_state;
305 std::size_t cnt = 0;
306 std::uint32_t prime_bracket_count = 1;
307 std::uint32_t second_bracket_count = 0;
308 CharT *ptr_first = parse_state.first;
309
310 if( *ptr_first == PrimLeft ) {
311 ++ptr_first;
312 }
313 while( true ) {
314 switch( *ptr_first ) {
315 case '\\':
316 ++ptr_first;
317 break;
318 case '"':
319 ++ptr_first;
320 if constexpr( traits::not_same<typename ParseState::exec_tag_t,
321 constexpr_exec_tag>::value ) {
323 ParseState::is_unchecked_input>( ParseState::exec_tag,
324 ptr_first, parse_state.last );
325 } else {
326 while( *ptr_first != '"' ) {
327 if( *ptr_first == '\\' ) {
328 ++ptr_first;
329 }
330 ++ptr_first;
331 }
332 }
333 break;
334 case ',':
335 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
336 ( second_bracket_count == 0 ) ) ) {
337 ++cnt;
338 }
339 break;
340 case PrimLeft:
341 ++prime_bracket_count;
342 break;
343 case PrimRight:
344 --prime_bracket_count;
345 if( prime_bracket_count == 0 ) {
346 ++ptr_first;
347 // We include the close primary bracket in the range so that
348 // subsequent parsers have a terminator inside their range
349 result.last = ptr_first;
350 result.counter = cnt;
351 parse_state.first = ptr_first;
352 return result;
353 }
354 break;
355 case SecLeft:
356 ++second_bracket_count;
357 break;
358 case SecRight:
359 --second_bracket_count;
360 break;
361 }
362 ++ptr_first;
363 }
364 // Should never get here, only loop exit is when PrimaryRight is found
365 // and count == 0
366 DAW_UNREACHABLE( );
367 }
368 };
369 } // namespace DAW_JSON_VER
370} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
ParseState & parse_state
Definition: daw_json_parse_class.h:182
DAW_ATTRIB_INLINE CharT * mem_skip_until_end_of_string(ExecTag const &tag, CharT *first, CharT *const last)
Definition: daw_not_const_ex_functions.h:390
constexpr DAW_ATTRIB_FLATINLINE CharT * mempbrk(CharT *first, CharT *last)
Definition: daw_json_string_util.h:199
constexpr DAW_ATTRIB_FLATINLINE CharT * memchr_unchecked(CharT *first, CharT *last)
Search for a character in a string.
Definition: daw_json_string_util.h:42
Definition: daw_from_json.h:22
Definition: daw_json_parse_policy_no_comments.h:30
static constexpr DAW_ATTRIB_FLATTEN ParseState skip_bracketed_item_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:301
static constexpr DAW_ATTRIB_FLATINLINE void move_to_next_of(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:94
static constexpr DAW_ATTRIB_FLATTEN ParseState skip_bracketed_item_checked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:144
static constexpr DAW_ATTRIB_FLATINLINE void trim_left_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:67
static constexpr DAW_ATTRIB_INLINE bool is_literal_end(char c)
Definition: daw_json_parse_policy_no_comments.h:137
static constexpr DAW_ATTRIB_FLATINLINE void trim_left_checked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:33
static constexpr DAW_ATTRIB_FLATINLINE void move_next_member_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:85
Definition: daw_json_exec_modes.h:19
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16