DAW JSON Link
daw_json_parse_policy_hash_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 #include <cstddef>
23 #include <cstdint>
24 #include <type_traits>
25 
26 namespace daw::json {
27  inline namespace DAW_JSON_VER {
29  template<typename ParseState>
30  DAW_ATTRIB_FLATINLINE static constexpr void
31  skip_comments_unchecked( ParseState &parse_state ) {
32  while( parse_state.front( ) == '#' ) {
33  parse_state.remove_prefix( );
34  parse_state.template move_to_next_of_unchecked<'\n'>( );
35  parse_state.remove_prefix( );
36  }
37  }
38 
39  template<typename ParseState>
40  DAW_ATTRIB_FLATINLINE static constexpr void
41  skip_comments_checked( ParseState &parse_state ) {
42  while( parse_state.has_more( ) and parse_state.front( ) == '#' ) {
43  parse_state.remove_prefix( );
44  parse_state.template move_to_next_of_checked<'\n'>( );
45  if( parse_state.front( ) == '\n' ) {
46  parse_state.remove_prefix( );
47  }
48  }
49  }
50 
51  template<typename ParseState>
52  DAW_ATTRIB_FLATINLINE static constexpr void
53  skip_comments( ParseState &parse_state ) {
54  if constexpr( ParseState::is_unchecked_input ) {
55  skip_comments_unchecked( parse_state );
56  } else {
57  skip_comments_checked( parse_state );
58  }
59  }
60 
61  public:
62  template<typename ParseState>
63  DAW_ATTRIB_FLATINLINE static constexpr void
64  trim_left_checked( ParseState &parse_state ) {
65  skip_comments_checked( parse_state );
66  while( parse_state.has_more( ) and parse_state.is_space_unchecked( ) ) {
67  parse_state.remove_prefix( );
68  skip_comments_checked( parse_state );
69  }
70  }
71 
72  template<typename ParseState>
73  DAW_ATTRIB_FLATINLINE static constexpr void
74  trim_left_unchecked( ParseState &parse_state ) {
75  skip_comments_unchecked( parse_state );
76  while( parse_state.is_space_unchecked( ) ) {
77  parse_state.remove_prefix( );
78  }
79  }
80 
81  template<typename ParseState>
82  DAW_ATTRIB_FLATINLINE static constexpr void
83  move_next_member_unchecked( ParseState &parse_state ) {
84  parse_state.move_next_member_or_end_unchecked( );
85  }
86 
87  template<char... keys, typename ParseState>
88  DAW_ATTRIB_FLATINLINE static constexpr void
89  move_to_next_of( ParseState &parse_state ) {
90  skip_comments( parse_state );
91 
92  daw_json_assert_weak( parse_state.has_more( ),
93  ErrorReason::UnexpectedEndOfData, parse_state );
94  while( not parse_policy_details::in<keys...>( parse_state.front( ) ) ) {
95  daw_json_assert_weak( parse_state.has_more( ),
96  ErrorReason::UnexpectedEndOfData, parse_state );
97  parse_state.remove_prefix( );
98  skip_comments( parse_state );
99  }
100  }
101 
102  DAW_ATTRIB_FLATINLINE static constexpr bool is_literal_end( char c ) {
103  return c == '\0' or c == ',' or c == ']' or c == '}' or c == '#';
104  }
105 
106  template<char PrimLeft, typename ParseState>
107  DAW_ATTRIB_FLATINLINE static constexpr ParseState
108  skip_bracketed_item_checked( ParseState &parse_state ) {
109  constexpr char PrimRight = PrimLeft == '{' ? '}' : ']';
110  constexpr char SecLeft = PrimLeft == '{' ? '[' : '{';
111  constexpr char SecRight = SecLeft == '{' ? '}' : ']';
112  using CharT = typename ParseState::CharT;
113  // Not checking for Left as it is required to be skipped already
114  auto result = parse_state;
115  std::size_t cnt = 0;
116  std::uint32_t prime_bracket_count = 1;
117  std::uint32_t second_bracket_count = 0;
118  CharT *ptr_first = parse_state.first;
119  CharT *const ptr_last = parse_state.last;
120  if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
121  return result;
122  }
123  if( *ptr_first == PrimLeft ) {
124  ++ptr_first;
125  }
126  while( DAW_LIKELY( ptr_first < ptr_last ) ) {
127  // TODO: use if/else if or put switch into IILE
128  switch( *ptr_first ) {
129  case '\\':
130  ++ptr_first;
131  break;
132  case '"':
133  ++ptr_first;
134  ptr_first = json_details::mem_skip_until_end_of_string<
135  ParseState::is_unchecked_input>( ParseState::exec_tag, ptr_first,
136  parse_state.last );
137  daw_json_ensure( ptr_first < ptr_last,
138  ErrorReason::UnexpectedEndOfData, parse_state );
139  break;
140  case ',':
141  if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
142  ++cnt;
143  }
144  break;
145  case PrimLeft:
146  ++prime_bracket_count;
147  break;
148  case PrimRight:
149  --prime_bracket_count;
150  if( prime_bracket_count == 0 ) {
151  daw_json_ensure( second_bracket_count == 0,
152  ErrorReason::InvalidBracketing, parse_state );
153  ++ptr_first;
154  // We include the close primary bracket in the range so that
155  // subsequent parsers have a terminator inside their range
156  result.last = ptr_first;
157  result.counter = cnt;
158  parse_state.first = ptr_first;
159  return result;
160  }
161  break;
162  case SecLeft:
163  ++second_bracket_count;
164  break;
165  case SecRight:
166  --second_bracket_count;
167  break;
168  case '#':
169  ++ptr_first;
170  while( ptr_first < ptr_last and *ptr_first != '\n' ) {
171  ++ptr_first;
172  }
173  if( ptr_first < ptr_last ) {
174  continue;
175  }
176  break;
177  }
178  ++ptr_first;
179  }
180  daw_json_ensure( ( prime_bracket_count == 0 ) &
181  ( second_bracket_count == 0 ),
182  ErrorReason::InvalidBracketing, parse_state );
183  // We include the close primary bracket in the range so that subsequent
184  // parsers have a terminator inside their range
185  result.last = ptr_first;
186  result.counter = cnt;
187  parse_state.first = ptr_first;
188  return result;
189  }
190 
191  template<char PrimLeft, typename ParseState>
192  DAW_ATTRIB_FLATINLINE static constexpr ParseState
193  skip_bracketed_item_unchecked( ParseState &parse_state ) {
194  // Not checking for Left as it is required to be skipped already
195  constexpr char PrimRight = PrimLeft == '{' ? '}' : ']';
196  constexpr char SecLeft = PrimLeft == '{' ? '[' : '{';
197  constexpr char SecRight = SecLeft == '{' ? '}' : ']';
198  using CharT = typename ParseState::CharT;
199  auto result = parse_state;
200  std::size_t cnt = 0;
201  std::uint32_t prime_bracket_count = 1;
202  std::uint32_t second_bracket_count = 0;
203  CharT *ptr_first = parse_state.first;
204  if( *ptr_first == PrimLeft ) {
205  ++ptr_first;
206  }
207  while( true ) {
208  switch( *ptr_first ) {
209  case '\\':
210  ++ptr_first;
211  break;
212  case '"':
213  ++ptr_first;
214  ptr_first = json_details::mem_skip_until_end_of_string<
215  ParseState::is_unchecked_input>( ParseState::exec_tag, ptr_first,
216  parse_state.last );
217  break;
218  case ',':
219  if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
220  ++cnt;
221  }
222  break;
223  case PrimLeft:
224  ++prime_bracket_count;
225  break;
226  case PrimRight:
227  --prime_bracket_count;
228  if( prime_bracket_count == 0 ) {
229  ++ptr_first;
230  // We include the close primary bracket in the range so that
231  // subsequent parsers have a terminator inside their range
232  result.last = ptr_first;
233  result.counter = cnt;
234  parse_state.first = ptr_first;
235  return result;
236  }
237  break;
238  case SecLeft:
239  ++second_bracket_count;
240  break;
241  case SecRight:
242  --second_bracket_count;
243  break;
244  case '#':
245  ++ptr_first;
246  while( *ptr_first != '\n' ) {
247  ++ptr_first;
248  }
249  break;
250  }
251  ++ptr_first;
252  }
253  DAW_UNREACHABLE( );
254  }
255  };
256  } // namespace DAW_JSON_VER
257 } // 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