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 "version.h"
12 
13 #include "daw_json_assert.h"
14 #include "daw_json_parse_common.h"
16 #include "daw_json_string_util.h"
18 
19 #include <daw/daw_attributes.h>
20 #include <daw/daw_function_table.h>
21 #include <daw/daw_likely.h>
22 #include <daw/daw_traits.h>
23 
24 #include <cstddef>
25 #include <cstdint>
26 #include <type_traits>
27 
28 namespace daw::json {
29  inline namespace DAW_JSON_VER {
31  template<typename ParseState>
32  DAW_ATTRIB_FLATINLINE static constexpr void
33  trim_left_checked( ParseState &parse_state ) {
34  if constexpr( ParseState::minified_document ) {
35  return;
36  } else {
37  using CharT = typename ParseState::CharT;
38  // SIMD here was much slower, most JSON has very minimal whitespace
39  CharT *first = parse_state.first;
40  daw_json_assert_weak( first, ErrorReason::Unknown );
41  CharT *const last = parse_state.last;
42 
43  // only used when not zero terminated string and gcc9 warns
44  (void)last;
45 
47  // Ensure that zero terminator isn't included in skipable value
48  while( DAW_UNLIKELY(
49  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
50  1U ) <= 0x1FU ) ) {
51 
52  ++first;
53  }
54  } else {
55  while(
56  DAW_LIKELY( first < last ) and
57  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
58  1U ) <= 0x1FU ) {
59  ++first;
60  }
61  }
62  parse_state.first = first;
63  }
64  }
65 
66  template<typename ParseState>
67  DAW_ATTRIB_FLATINLINE static constexpr void
68  trim_left_unchecked( ParseState &parse_state ) {
69  if constexpr( ParseState::minified_document ) {
70  return;
71  } else {
72  using CharT = typename ParseState::CharT;
73  CharT *first = parse_state.first;
74  while( DAW_UNLIKELY(
75  ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
76  1U ) <= 0x1F ) ) {
77 
78  ++first;
79  }
80  parse_state.first = first;
81  }
82  }
83 
84  template<typename ParseState>
85  DAW_ATTRIB_FLATINLINE static constexpr void
86  move_next_member_unchecked( ParseState &parse_state ) {
87  parse_state.first =
88  json_details::memchr_unchecked<'"', typename ParseState::exec_tag_t,
89  ParseState::expect_long_strings>(
90  parse_state.first, parse_state.last );
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( daw::traits::not_same<typename ParseState::exec_tag_t,
102  constexpr_exec_tag>::value ) {
103  parse_state.first =
104  json_details::mempbrk<ParseState::is_unchecked_input,
105  typename ParseState::exec_tag_t,
106  ParseState::expect_long_strings, keys...>(
107  parse_state.first, parse_state.last );
108  } else {
109  CharT *first = parse_state.first;
110  CharT *const last = parse_state.last;
111 
112  // silencing gcc9 unused warning. last is used inside if constexpr
113  // blocks
114  (void)last;
115 
117  daw_json_assert_weak( first < last and *first != '\0',
118  ErrorReason::UnexpectedEndOfData,
119  parse_state );
120  while( not parse_policy_details::in<keys...>( *first ) ) {
121  ++first;
122  }
123  daw_json_assert_weak( *first != 0, ErrorReason::UnexpectedEndOfData,
124  parse_state );
125  } else {
127  first < last, ErrorReason::UnexpectedEndOfData, parse_state );
128  while( not parse_policy_details::in<keys...>( *first ) ) {
129  ++first;
131  first < last, ErrorReason::UnexpectedEndOfData, parse_state );
132  }
133  }
134  parse_state.first = first;
135  }
136  }
137 
138  DAW_ATTRIB_INLINE static constexpr bool is_literal_end( char c ) {
139  return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
140  }
141 
142  template<char PrimLeft, typename ParseState>
143  DAW_ATTRIB_FLATTEN static constexpr ParseState
144  skip_bracketed_item_checked( ParseState &parse_state ) {
145  constexpr char PrimRight = PrimLeft == '{' ? '}' : ']';
146  constexpr char SecLeft = PrimLeft == '{' ? '[' : '{';
147  constexpr char SecRight = SecLeft == '{' ? '}' : ']';
148 
149  using CharT = typename ParseState::CharT;
150  // Not checking for Left as it is required to be skipped already
151  CharT *ptr_first = parse_state.first;
152  CharT *const ptr_last = parse_state.last;
153  if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
154  return parse_state;
155  }
156  auto result = parse_state;
157  std::size_t cnt = 0;
158  std::uint32_t prime_bracket_count = 1;
159  std::uint32_t second_bracket_count = 0;
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  ptr_first = json_details::mem_skip_until_end_of_string<
172  ParseState::is_unchecked_input>( ParseState::exec_tag, ptr_first,
173  ptr_last );
174  daw_json_ensure( ptr_first < ptr_last and *ptr_first == '"',
175  ErrorReason::UnexpectedEndOfData, parse_state );
176  break;
177  case ',':
178  if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
179  ( 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  ++ptr_first;
190  daw_json_ensure( second_bracket_count == 0,
191  ErrorReason::InvalidBracketing, parse_state );
192  result.last = ptr_first;
193  result.counter = cnt;
194  parse_state.first = ptr_first;
195  return result;
196  }
197  break;
198  case SecLeft:
199  ++second_bracket_count;
200  break;
201  case SecRight:
202  --second_bracket_count;
203  break;
204  }
205  ++ptr_first;
206  }
207  daw_json_ensure( ( prime_bracket_count == 0 ) &
208  ( second_bracket_count == 0 ),
209  ErrorReason::InvalidBracketing, parse_state );
210  // We include the close primary bracket in the range so that subsequent
211  // parsers have a terminator inside their range
212  result.last = ptr_first;
213  result.counter = cnt;
214  parse_state.first = ptr_first;
215  return result;
216  }
217 
218  template<char PrimLeft, typename ParseState>
219  DAW_ATTRIB_NOINLINE static constexpr ParseState
220  skip_bracketed_item_unchecked( ParseState &parse_state ) {
221  // Not checking for Left as it is required to be skipped already
222  constexpr char PrimRight = PrimLeft == '{' ? '}' : ']';
223  constexpr char SecLeft = PrimLeft == '{' ? '[' : '{';
224  constexpr char SecRight = SecLeft == '{' ? '}' : ']';
225  using CharT = typename ParseState::CharT;
226  auto result = parse_state;
227  std::size_t cnt = 0;
228  std::uint32_t prime_bracket_count = 1;
229  std::uint32_t second_bracket_count = 0;
230  CharT *ptr_first = parse_state.first;
231 
232  if( *ptr_first == PrimLeft ) {
233  ++ptr_first;
234  }
235  while( true ) {
236  switch( *ptr_first ) {
237  case '\\':
238  ++ptr_first;
239  break;
240  case '"':
241  ++ptr_first;
242  ptr_first = json_details::mem_skip_until_end_of_string<
243  ParseState::is_unchecked_input>( ParseState::exec_tag, ptr_first,
244  parse_state.last );
245  break;
246  case ',':
247  if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
248  ( second_bracket_count == 0 ) ) ) {
249  ++cnt;
250  }
251  break;
252  case PrimLeft:
253  ++prime_bracket_count;
254  break;
255  case PrimRight:
256  --prime_bracket_count;
257  if( prime_bracket_count == 0 ) {
258  ++ptr_first;
259  // We include the close primary bracket in the range so that
260  // subsequent parsers have a terminator inside their range
261  result.last = ptr_first;
262  result.counter = cnt;
263  parse_state.first = ptr_first;
264  return result;
265  }
266  break;
267  case SecLeft:
268  ++second_bracket_count;
269  break;
270  case SecRight:
271  --second_bracket_count;
272  break;
273  }
274  ++ptr_first;
275  }
276  // Should never get here, only loop exit is when PrimaryRight is found
277  // and count == 0
278  DAW_UNREACHABLE( );
279  }
280  };
281  } // namespace DAW_JSON_VER
282 } // 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.
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
Customization point traits.
static constexpr DAW_ATTRIB_NOINLINE ParseState skip_bracketed_item_unchecked(ParseState &parse_state)
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25