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