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