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"
12 #include "daw_json_parse_common.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 
23 namespace 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
130  move_to_next_of( ParseState &parse_state ) {
131  skip_comments( parse_state );
132  daw_json_assert_weak( parse_state.has_more( ),
133  ErrorReason::UnexpectedEndOfData, parse_state );
134  while( not parse_policy_details::in<keys...>( parse_state.front( ) ) ) {
135  daw_json_assert_weak( parse_state.has_more( ),
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,
172  constexpr_exec_tag> ) {
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,
276  constexpr_exec_tag> ) {
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:189
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:178
ParseState & parse_state
Definition: daw_json_parse_class.h:201
DAW_ATTRIB_FLATINLINE CharT * mem_skip_until_end_of_string(ExecTag const &tag, CharT *first, CharT *const last)
Definition: daw_not_const_ex_functions.h:360
Definition: daw_from_json.h:22
Definition: daw_json_exec_modes.h:19
#define DAW_JSON_VER
Definition: version.h:11