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 "version.h"
12 
13 #include "daw_json_assert.h"
14 #include "daw_json_parse_common.h"
17 
18 #include <daw/daw_attributes.h>
19 #include <daw/daw_likely.h>
20 #include <daw/daw_traits.h>
21 
22 namespace 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:25