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<char PrimLeft, typename ParseState>
150 DAW_ATTRIB_FLATINLINE static constexpr ParseState
151 skip_bracketed_item_checked( ParseState &parse_state ) {
152 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
153 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
154 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
155
156 // Not checking for Left as it is required to be skipped already
157 auto result = parse_state;
158 std::size_t cnt = 0;
159 std::uint32_t prime_bracket_count = 1;
160 std::uint32_t second_bracket_count = 0;
161 auto ptr_first = daw::not_null<char const *>( parse_state.first );
162 auto const ptr_last = daw::not_null<char const *>( parse_state.last );
163 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
164 return result;
165 }
166 if( *ptr_first == PrimLeft ) {
167 ++ptr_first;
168 }
169 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
170 switch( *ptr_first ) {
171 case '\\':
172 ++ptr_first;
173 break;
174 case '"':
175 ++ptr_first;
176 ptr_first = json_details::mem_skip_until_end_of_string<
177 ParseState::is_unchecked_input,
178 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
179 daw_json_ensure( ptr_first < ptr_last,
180 ErrorReason::UnexpectedEndOfData,
181 parse_state );
182 break;
183 case ',':
184 if( prime_bracket_count == 1 and 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 daw_json_ensure( second_bracket_count == 0,
195 ErrorReason::InvalidBracketing,
196 parse_state );
197 ++ptr_first;
198 // We include the close primary bracket in the range so that
199 // subsequent parsers have a terminator inside their range
200 result.last = ptr_first;
201 result.counter = cnt;
202 parse_state.first = ptr_first;
203 return result;
204 }
205 break;
206 case SecLeft::value:
207 ++second_bracket_count;
208 break;
209 case SecRight::value:
210 --second_bracket_count;
211 break;
212 case '/':
213 ++ptr_first;
214 daw_json_ensure( ptr_first < ptr_last,
215 ErrorReason::UnexpectedEndOfData,
216 parse_state );
217 switch( *ptr_first ) {
218 case '/':
219 ++ptr_first;
220 while( ( ptr_last - ptr_first ) > 1 and *ptr_first != '\n' ) {
221 ++ptr_first;
222 }
223 break;
224 case '*':
225 ++ptr_first;
226 while( ( ptr_last - ptr_first ) >= 3 and *ptr_first != '*' and
227 *std::next( ptr_first.get( ) ) != '/' ) {
228 ++ptr_first;
229 }
230 break;
231 default:
232 ++ptr_first;
233 }
234 break;
235 }
236 ++ptr_first;
237 }
238 daw_json_assert_weak( ( prime_bracket_count == 0 ) &
239 ( second_bracket_count == 0 ),
240 ErrorReason::InvalidBracketing,
241 parse_state );
242 // We include the close primary bracket in the range so that subsequent
243 // parsers have a terminator inside their range
244 result.last = ptr_first;
245 result.counter = cnt;
246 parse_state.first = ptr_first;
247 return result;
248 }
249
250 template<char PrimLeft, typename ParseState>
251 DAW_ATTRIB_FLATINLINE static constexpr ParseState
252 skip_bracketed_item_unchecked( ParseState &parse_state ) {
253 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
254 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
255 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
256
257 // Not checking for Left as it is required to be skipped already
258 auto result = parse_state;
259 std::size_t cnt = 0;
260 std::uint32_t prime_bracket_count = 1;
261 std::uint32_t second_bracket_count = 0;
262 auto ptr_first =
263 daw::not_null<char const *>( daw::never_null, parse_state.first );
264 auto const ptr_last =
265 daw::not_null<char const *>( daw::never_null, parse_state.last );
266 if( *ptr_first == PrimLeft ) {
267 ++ptr_first;
268 }
269 while( true ) {
270 switch( *ptr_first ) {
271 case '\\':
272 ++ptr_first;
273 break;
274 case '"':
275 ++ptr_first;
276 ptr_first = json_details::mem_skip_until_end_of_string<
277 ParseState::is_unchecked_input,
278 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
279 break;
280 case ',':
281 if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
282 ++cnt;
283 }
284 break;
285 case PrimLeft:
286 ++prime_bracket_count;
287 break;
288 case PrimRight::value:
289 --prime_bracket_count;
290 if( prime_bracket_count == 0 ) {
291 ++ptr_first;
292 // We include the close primary bracket in the range so that
293 // subsequent parsers have a terminator inside their range
294 result.last = ptr_first;
295 result.counter = cnt;
296 parse_state.first = ptr_first;
297 return result;
298 }
299 break;
300 case SecLeft::value:
301 ++second_bracket_count;
302 break;
303 case SecRight::value:
304 --second_bracket_count;
305 break;
306 case '/':
307 ++ptr_first;
308 switch( *ptr_first ) {
309 case '/':
310 ++ptr_first;
311 while( *ptr_first != '\n' ) {
312 ++ptr_first;
313 }
314 break;
315 case '*':
316 ++ptr_first;
317 while( *ptr_first != '*' and
318 *std::next( ptr_first.get( ) ) != '/' ) {
319 ++ptr_first;
320 }
321 break;
322 default:
323 ++ptr_first;
324 }
325 break;
326 }
327 ++ptr_first;
328 }
329 DAW_UNREACHABLE( );
330 }
331 };
332 } // namespace DAW_JSON_VER
333} // 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