DAW JSON Link
daw_json_parse_policy_no_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_function_table.h>
19 #include <daw/daw_likely.h>
20 #include <daw/daw_traits.h>
21 
22 #include <ciso646>
23 #include <cstddef>
24 #include <cstdint>
25 #include <type_traits>
26 
27 namespace daw::json {
28  inline namespace DAW_JSON_VER {
29  struct NoCommentSkippingPolicy final {
30  template<typename ParseState>
31  DAW_ATTRIB_FLATINLINE static constexpr void
32  trim_left_checked( ParseState &parse_state ) {
33  if constexpr( ParseState::minified_document ) {
34  return;
35  } else {
36  using CharT = typename ParseState::CharT;
37  // SIMD here was much slower, most JSON has very minimal whitespace
38  CharT *first = parse_state.first;
39  CharT *const last = parse_state.last;
40 
41  // only used when not zero terminated string and gcc9 warns
42  (void)last;
43 
44  if constexpr( ParseState::is_zero_terminated_string ) {
45  // Ensure that zero terminator isn't included in skipable value
46  while( DAW_UNLIKELY(
47  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
48  1U ) <= 0x1FU ) ) {
49 
50  ++first;
51  }
52  } else {
53  while(
54  DAW_LIKELY( first < last ) and
55  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
56  1U ) <= 0x1FU ) {
57  ++first;
58  }
59  }
60  parse_state.first = first;
61  }
62  }
63 
64  template<typename ParseState>
65  DAW_ATTRIB_FLATINLINE static constexpr void
67  if constexpr( ParseState::minified_document ) {
68  return;
69  } else {
70  using CharT = typename ParseState::CharT;
71  CharT *first = parse_state.first;
72  while( DAW_UNLIKELY(
73  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
74  1U ) <= 0x1F ) ) {
75 
76  ++first;
77  }
78  parse_state.first = first;
79  }
80  }
81 
82  template<typename ParseState>
83  DAW_ATTRIB_FLATINLINE static constexpr void
85  using CharT = typename ParseState::CharT;
86  CharT *first = parse_state.first;
87  while( *first != '"' ) {
88  ++first;
89  }
90  parse_state.first = first;
91  }
92 
93  template<char... keys, typename ParseState>
94  DAW_ATTRIB_FLATINLINE static constexpr void
95  move_to_next_of( ParseState &parse_state ) {
96  static_assert( sizeof...( keys ) > 0 );
97  static_assert( sizeof...( keys ) <= 16 );
98 
99  using CharT = typename ParseState::CharT;
100 
101  if constexpr( traits::not_same<typename ParseState::exec_tag_t,
102  constexpr_exec_tag>::value ) {
103  parse_state.first =
104  json_details::mem_move_to_next_of<ParseState::is_unchecked_input,
105  keys...>(
106  ParseState::exec_tag, parse_state.first, parse_state.last );
107  } else {
108  CharT *first = parse_state.first;
109  CharT *const last = parse_state.last;
110 
111  // silencing gcc9 unused warning. last is used inside if constexpr
112  // blocks
113  (void)last;
114 
115  if( ParseState::is_zero_terminated_string ) {
116  daw_json_assert_weak( first < last and *first != '\0',
117  ErrorReason::UnexpectedEndOfData,
118  parse_state );
119  while( not parse_policy_details::in<keys...>( *first ) ) {
120  ++first;
121  }
122  daw_json_assert_weak( *first != 0, ErrorReason::UnexpectedEndOfData,
123  parse_state );
124  } else {
126  first < last, ErrorReason::UnexpectedEndOfData, parse_state );
127  while( not parse_policy_details::in<keys...>( *first ) ) {
128  ++first;
130  first < last, ErrorReason::UnexpectedEndOfData, parse_state );
131  }
132  }
133  parse_state.first = first;
134  }
135  }
136 
137  DAW_ATTRIB_FLATINLINE static constexpr bool is_literal_end( char c ) {
138  return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
139  }
140 
141  template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
142  typename ParseState>
143  DAW_ATTRIB_FLATTEN static constexpr ParseState
145  using CharT = typename ParseState::CharT;
146  // Not checking for Left as it is required to be skipped already
147  auto result = parse_state;
148  std::size_t cnt = 0;
149  std::uint32_t prime_bracket_count = 1;
150  std::uint32_t second_bracket_count = 0;
151  CharT *ptr_first = parse_state.first;
152  CharT *const ptr_last = parse_state.last;
153 
154  if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
155  return result;
156  }
157  if( *ptr_first == PrimLeft ) {
158  ++ptr_first;
159  }
160  if constexpr( ParseState::is_zero_terminated_string ) {
161  daw_json_assert( ptr_first < ptr_last,
162  ErrorReason::UnexpectedEndOfData, parse_state );
163  while( *ptr_first != 0 ) {
164  switch( *ptr_first ) {
165  case '\\':
166  ++ptr_first;
167  break;
168  case '"':
169  ++ptr_first;
170  if constexpr( traits::not_same<typename ParseState::exec_tag_t,
171  constexpr_exec_tag>::value ) {
173  ParseState::is_unchecked_input>(
174  ParseState::exec_tag, ptr_first, parse_state.last );
175  } else {
176  char c = *ptr_first;
177  while( ( c != '\0' ) & ( c != '"' ) ) {
178  if( c == '\\' ) {
179  if( ptr_first + 1 < ptr_last ) {
180  ptr_first += 2;
181  c = *ptr_first;
182  continue;
183  } else {
184  ptr_first = ptr_last;
185  break;
186  }
187  }
188  ++ptr_first;
189  c = *ptr_first;
190  }
191  }
192  daw_json_assert( ( *ptr_first != '\0' ) & ( *ptr_first == '"' ),
193  ErrorReason::UnexpectedEndOfData, parse_state );
194  break;
195  case ',':
196  if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
197  ( second_bracket_count == 0 ) ) ) {
198  ++cnt;
199  }
200  break;
201  case PrimLeft:
202  ++prime_bracket_count;
203  break;
204  case PrimRight:
205  --prime_bracket_count;
206  if( prime_bracket_count == 0 ) {
207  ++ptr_first;
208  daw_json_assert( second_bracket_count == 0,
209  ErrorReason::InvalidBracketing, parse_state );
210  result.last = ptr_first;
211  result.counter = cnt;
212  parse_state.first = ptr_first;
213  return result;
214  }
215  break;
216  case SecLeft:
217  ++second_bracket_count;
218  break;
219  case SecRight:
220  --second_bracket_count;
221  break;
222  }
223  ++ptr_first;
224  }
225  } else {
226  while( DAW_LIKELY( ptr_first < ptr_last ) ) {
227  switch( *ptr_first ) {
228  case '\\':
229  ++ptr_first;
230  break;
231  case '"':
232  ++ptr_first;
233  if constexpr( traits::not_same<typename ParseState::exec_tag_t,
234  constexpr_exec_tag>::value ) {
236  ParseState::is_unchecked_input>(
237  ParseState::exec_tag, ptr_first, parse_state.last );
238  } else {
239  while( DAW_LIKELY( ptr_first < ptr_last ) and
240  *ptr_first != '"' ) {
241  if( *ptr_first == '\\' ) {
242  if( ptr_first + 1 < ptr_last ) {
243  ptr_first += 2;
244  continue;
245  } else {
246  ptr_first = ptr_last;
247  break;
248  }
249  }
250  ++ptr_first;
251  }
252  }
253  daw_json_assert( ptr_first < ptr_last and *ptr_first == '"',
254  ErrorReason::UnexpectedEndOfData, parse_state );
255  break;
256  case ',':
257  if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
258  ( second_bracket_count == 0 ) ) ) {
259  ++cnt;
260  }
261  break;
262  case PrimLeft:
263  ++prime_bracket_count;
264  break;
265  case PrimRight:
266  --prime_bracket_count;
267  if( prime_bracket_count == 0 ) {
268  ++ptr_first;
269  daw_json_assert( second_bracket_count == 0,
270  ErrorReason::InvalidBracketing, parse_state );
271  result.last = ptr_first;
272  result.counter = cnt;
273  parse_state.first = ptr_first;
274  return result;
275  }
276  break;
277  case SecLeft:
278  ++second_bracket_count;
279  break;
280  case SecRight:
281  --second_bracket_count;
282  break;
283  }
284  ++ptr_first;
285  }
286  }
287  daw_json_assert( ( prime_bracket_count == 0 ) &
288  ( second_bracket_count == 0 ),
289  ErrorReason::InvalidBracketing, parse_state );
290  // We include the close primary bracket in the range so that subsequent
291  // parsers have a terminator inside their range
292  result.last = ptr_first;
293  result.counter = cnt;
294  parse_state.first = ptr_first;
295  return result;
296  }
297 
298  template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
299  typename ParseState>
300  DAW_ATTRIB_FLATTEN static constexpr ParseState
302  // Not checking for Left as it is required to be skipped already
303  using CharT = typename ParseState::CharT;
304  auto result = parse_state;
305  std::size_t cnt = 0;
306  std::uint32_t prime_bracket_count = 1;
307  std::uint32_t second_bracket_count = 0;
308  CharT *ptr_first = parse_state.first;
309 
310  if( *ptr_first == PrimLeft ) {
311  ++ptr_first;
312  }
313  while( true ) {
314  switch( *ptr_first ) {
315  case '\\':
316  ++ptr_first;
317  break;
318  case '"':
319  ++ptr_first;
320  if constexpr( traits::not_same<typename ParseState::exec_tag_t,
321  constexpr_exec_tag>::value ) {
323  ParseState::is_unchecked_input>( ParseState::exec_tag,
324  ptr_first, parse_state.last );
325  } else {
326  while( *ptr_first != '"' ) {
327  if( *ptr_first == '\\' ) {
328  ++ptr_first;
329  }
330  ++ptr_first;
331  }
332  }
333  break;
334  case ',':
335  if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
336  ( second_bracket_count == 0 ) ) ) {
337  ++cnt;
338  }
339  break;
340  case PrimLeft:
341  ++prime_bracket_count;
342  break;
343  case PrimRight:
344  --prime_bracket_count;
345  if( prime_bracket_count == 0 ) {
346  ++ptr_first;
347  // We include the close primary bracket in the range so that
348  // subsequent parsers have a terminator inside their range
349  result.last = ptr_first;
350  result.counter = cnt;
351  parse_state.first = ptr_first;
352  return result;
353  }
354  break;
355  case SecLeft:
356  ++second_bracket_count;
357  break;
358  case SecRight:
359  --second_bracket_count;
360  break;
361  }
362  ++ptr_first;
363  }
364  // Should never get here, only loop exit is when PrimaryRight is found
365  // and count == 0
366  DAW_UNREACHABLE( );
367  }
368  };
369  } // namespace DAW_JSON_VER
370 } // namespace daw::json
#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_move_to_next_of(runtime_exec_tag, CharT *first, CharT *last)
Definition: daw_not_const_ex_functions.h:323
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_parse_policy_no_comments.h:29
static constexpr DAW_ATTRIB_FLATTEN ParseState skip_bracketed_item_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:301
static constexpr DAW_ATTRIB_FLATINLINE void move_to_next_of(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:95
static constexpr DAW_ATTRIB_FLATTEN ParseState skip_bracketed_item_checked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:144
static constexpr DAW_ATTRIB_FLATINLINE void trim_left_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:66
static constexpr DAW_ATTRIB_FLATINLINE void trim_left_checked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:32
static constexpr DAW_ATTRIB_FLATINLINE bool is_literal_end(char c)
Definition: daw_json_parse_policy_no_comments.h:137
static constexpr DAW_ATTRIB_FLATINLINE void move_next_member_unchecked(ParseState &parse_state)
Definition: daw_json_parse_policy_no_comments.h:84
Definition: daw_json_exec_modes.h:19
#define DAW_JSON_VER
Definition: version.h:11