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