DAW JSON Link
Loading...
Searching...
No Matches
daw_json_parse_policy_cpp_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
17
18#include <daw/daw_attributes.h>
19#include <daw/daw_constant.h>
20#include <daw/daw_likely.h>
21#include <daw/daw_not_null.h>
22#include <daw/daw_traits.h>
23
24namespace daw::json {
25 inline namespace DAW_JSON_VER {
26 /***
27 * Allow skipping C++ style comments in JSON document
28 */
30 template<typename ParseState>
31 DAW_ATTRIB_FLATINLINE static constexpr void
32 skip_comments_unchecked( ParseState &parse_state ) {
33 while( parse_state.front( ) == '/' ) {
34 switch( *( parse_state.first + 1 ) ) {
35 case '/':
36 parse_state.template move_to_next_of_unchecked<'\n'>( );
37 parse_state.remove_prefix( );
38 break;
39 case '*':
40 parse_state.remove_prefix( 2 );
41 while( true ) {
42 parse_state.template move_to_next_of_unchecked<'*'>( );
43 parse_state.remove_prefix( );
44 if( parse_state.front( ) == '/' ) {
45 parse_state.remove_prefix( );
46 break;
47 }
48 parse_state.remove_prefix( );
49 }
50 break;
51 default:
52 return;
53 }
54 }
55 }
56
57 template<typename ParseState>
58 DAW_ATTRIB_FLATINLINE static constexpr void
59 skip_comments_checked( ParseState &parse_state ) {
60 while( parse_state.has_more( ) and parse_state.front( ) == '/' ) {
61 if( not parse_state.has_more( ) ) {
62 return;
63 }
64 switch( *( parse_state.first + 1 ) ) {
65 case '/':
66 parse_state.template move_to_next_of_checked<'\n'>( );
67 if( parse_state.has_more( ) ) {
68 parse_state.remove_prefix( );
69 }
70 break;
71 case '*':
72 parse_state.remove_prefix( 2 );
73 while( parse_state.has_more( ) ) {
74 parse_state.template move_to_next_of_checked<'*'>( );
75 if( parse_state.has_more( ) ) {
76 parse_state.remove_prefix( );
77 }
78 if( not parse_state.has_more( ) ) {
79 break;
80 } else if( parse_state.front( ) == '/' ) {
81 parse_state.remove_prefix( );
82 break;
83 }
84 parse_state.remove_prefix( );
85 }
86 break;
87 default:
88 return;
89 }
90 }
91 }
92
93 template<typename ParseState>
94 DAW_ATTRIB_FLATINLINE static constexpr void
95 skip_comments( ParseState &parse_state ) {
96 if constexpr( ParseState::is_unchecked_input ) {
97 skip_comments_unchecked( parse_state );
98 } else {
99 skip_comments_checked( parse_state );
100 }
101 }
102
103 public:
104 template<typename ParseState>
105 DAW_ATTRIB_FLATINLINE static constexpr void
106 trim_left_checked( ParseState &parse_state ) {
107 skip_comments_checked( parse_state );
108 while( parse_state.has_more( ) and parse_state.is_space_unchecked( ) ) {
109 parse_state.remove_prefix( );
110 skip_comments_checked( parse_state );
111 }
112 }
113
114 template<typename ParseState>
115 DAW_ATTRIB_FLATINLINE static constexpr void
116 trim_left_unchecked( ParseState &parse_state ) {
117 skip_comments_unchecked( parse_state );
118 while( parse_state.is_space_unchecked( ) ) {
119 parse_state.remove_prefix( );
120 }
121 }
122
123 template<typename ParseState>
124 DAW_ATTRIB_FLATINLINE static constexpr void
125 move_next_member_unchecked( ParseState &parse_state ) {
126 parse_state.move_next_member_or_end_unchecked( );
127 }
128
129 template<char... keys, typename ParseState>
130 DAW_ATTRIB_FLATINLINE static constexpr void
131 move_to_next_of( ParseState &parse_state ) {
132 skip_comments( parse_state );
133 daw_json_assert_weak( parse_state.has_more( ),
134 ErrorReason::UnexpectedEndOfData,
135 parse_state );
136 while( not parse_policy_details::in<keys...>( parse_state.front( ) ) ) {
137 daw_json_assert_weak( parse_state.has_more( ),
138 ErrorReason::UnexpectedEndOfData,
139 parse_state );
140 parse_state.remove_prefix( );
141 skip_comments( parse_state );
142 }
143 }
144
145 DAW_ATTRIB_FLATINLINE static constexpr bool is_literal_end( char c ) {
146 return c == '\0' or c == ',' or c == ']' or c == '}' or c == '#';
147 }
148
149 template<json_details::SkipBracketedType BracketedType,
150 typename ParseState>
151 DAW_ATTRIB_FLATINLINE static constexpr ParseState
152 skip_bracketed_item_checked( ParseState &parse_state ) {
153 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
154 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
155 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
156 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
157 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
158 // Not checking for Left as it is required to be skipped already
159 auto result = parse_state;
160 std::size_t cnt = 0;
161 std::uint32_t prime_bracket_count = 1;
162 std::uint32_t second_bracket_count = 0;
163 auto ptr_first = daw::not_null( parse_state.first );
164 auto const ptr_last = daw::not_null( parse_state.last );
165 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
166 return result;
167 }
168 if( *ptr_first == PrimLeft ) {
169 ++ptr_first;
170 }
171 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
172 switch( *ptr_first ) {
173 case '\\':
174 ++ptr_first;
175 break;
176 case '"':
177 ++ptr_first;
178 if constexpr( std::is_same_v<char *,
179 typename ParseState::iterator> ) {
180 auto skip_ptr = json_details::mem_skip_until_end_of_string<
181 ParseState::is_unchecked_input,
182 typename ParseState::exec_tag_t>( ptr_first.get( ),
183 ptr_last.get( ) );
184 ptr_first += skip_ptr - ptr_first.get( );
185 } else {
186 ptr_first = json_details::mem_skip_until_end_of_string<
187 ParseState::is_unchecked_input,
188 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
189 }
190 daw_json_ensure( ptr_first < ptr_last,
191 ErrorReason::UnexpectedEndOfData,
192 parse_state );
193 break;
194 case ',':
195 if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
196 ++cnt;
197 }
198 break;
199 case PrimLeft:
200 ++prime_bracket_count;
201 break;
202 case PrimRight::value:
203 --prime_bracket_count;
204 if( prime_bracket_count == 0 ) {
205 daw_json_ensure( second_bracket_count == 0,
206 ErrorReason::InvalidBracketing,
207 parse_state );
208 ++ptr_first;
209 // We include the close primary bracket in the range so that
210 // subsequent parsers have a terminator inside their range
211 result.last = ptr_first;
212 result.counter = cnt;
213 parse_state.first = ptr_first;
214 return result;
215 }
216 break;
217 case SecLeft::value:
218 ++second_bracket_count;
219 break;
220 case SecRight::value:
221 --second_bracket_count;
222 break;
223 case '/':
224 ++ptr_first;
225 daw_json_ensure( ptr_first < ptr_last,
226 ErrorReason::UnexpectedEndOfData,
227 parse_state );
228 switch( *ptr_first ) {
229 case '/':
230 ++ptr_first;
231 while( ( ptr_last - ptr_first ) > 1 and *ptr_first != '\n' ) {
232 ++ptr_first;
233 }
234 break;
235 case '*':
236 ++ptr_first;
237 while( ( ptr_last - ptr_first ) >= 3 and *ptr_first != '*' and
238 *std::next( ptr_first.get( ) ) != '/' ) {
239 ++ptr_first;
240 }
241 break;
242 default:
243 ++ptr_first;
244 }
245 break;
246 }
247 ++ptr_first;
248 }
249 daw_json_assert_weak( ( prime_bracket_count == 0 ) &
250 ( second_bracket_count == 0 ),
251 ErrorReason::InvalidBracketing,
252 parse_state );
253 // We include the close primary bracket in the range so that subsequent
254 // parsers have a terminator inside their range
255 result.last = ptr_first;
256 result.counter = cnt;
257 parse_state.first = ptr_first;
258 return result;
259 }
260
261 template<json_details::SkipBracketedType BracketedType,
262 typename ParseState>
263 DAW_ATTRIB_FLATINLINE static constexpr ParseState
264 skip_bracketed_item_unchecked( ParseState &parse_state ) {
265 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
266 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
267 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
268 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
269 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
270
271 // Not checking for Left as it is required to be skipped already
272 auto result = parse_state;
273 std::size_t cnt = 0;
274 std::uint32_t prime_bracket_count = 1;
275 std::uint32_t second_bracket_count = 0;
276 auto ptr_first = daw::not_null( daw::never_null, parse_state.first );
277 auto const ptr_last =
278 daw::not_null( daw::never_null, parse_state.last );
279 if( *ptr_first == PrimLeft ) {
280 ++ptr_first;
281 }
282 while( true ) {
283 switch( *ptr_first ) {
284 case '\\':
285 ++ptr_first;
286 break;
287 case '"':
288 ++ptr_first;
289 if constexpr( std::is_same_v<char *,
290 typename ParseState::iterator> ) {
291 auto skip_ptr = json_details::mem_skip_until_end_of_string<
292 ParseState::is_unchecked_input,
293 typename ParseState::exec_tag_t>( ptr_first.get( ),
294 ptr_last.get( ) );
295 ptr_first += skip_ptr - ptr_first.get( );
296 } else {
297 ptr_first = json_details::mem_skip_until_end_of_string<
298 ParseState::is_unchecked_input,
299 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
300 }
301 break;
302 case ',':
303 if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
304 ++cnt;
305 }
306 break;
307 case PrimLeft:
308 ++prime_bracket_count;
309 break;
310 case PrimRight::value:
311 --prime_bracket_count;
312 if( prime_bracket_count == 0 ) {
313 ++ptr_first;
314 // We include the close primary bracket in the range so that
315 // subsequent parsers have a terminator inside their range
316 result.last = ptr_first;
317 result.counter = cnt;
318 parse_state.first = ptr_first;
319 return result;
320 }
321 break;
322 case SecLeft::value:
323 ++second_bracket_count;
324 break;
325 case SecRight::value:
326 --second_bracket_count;
327 break;
328 case '/':
329 ++ptr_first;
330 switch( *ptr_first ) {
331 case '/':
332 ++ptr_first;
333 while( *ptr_first != '\n' ) {
334 ++ptr_first;
335 }
336 break;
337 case '*':
338 ++ptr_first;
339 while( *ptr_first != '*' and
340 *std::next( ptr_first.get( ) ) != '/' ) {
341 ++ptr_first;
342 }
343 break;
344 default:
345 ++ptr_first;
346 }
347 break;
348 }
349 ++ptr_first;
350 }
351 DAW_UNREACHABLE( );
352 }
353 };
354 } // namespace DAW_JSON_VER
355} // 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.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20