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 
16 #include <daw/daw_function_table.h>
17 #include <daw/daw_hide.h>
18 
19 #include <ciso646>
20 #include <cstddef>
21 #include <cstdint>
22 #include <type_traits>
23 
24 namespace daw::json {
25  template<bool DocumentIsMinified>
27  /***
28  * The document has no whitespace between members(minified)
29  */
30  static constexpr bool document_is_minified = DocumentIsMinified;
31  template<typename Range>
32  DAW_ATTRIBUTE_FLATTEN static constexpr void
33  trim_left_checked( Range &rng ) {
34  if constexpr( not document_is_minified ) {
35  // SIMD here was much slower, most JSON has very minimal whitespace
36  char const *first = rng.first;
37  char const *const last = rng.last;
38  while( DAW_JSON_LIKELY( first < last ) and
39  static_cast<unsigned char>( *first ) <= 0x20U ) {
40  ++first;
41  }
42  rng.first = first;
43  }
44  }
45 
46  template<typename Range>
47  DAW_ATTRIBUTE_FLATTEN static constexpr void
48  trim_left_unchecked( Range &rng ) {
49  if constexpr( not document_is_minified ) {
50  char const *first = rng.first;
51  while( static_cast<unsigned char>( *first ) <= 0x20 ) {
52  ++first;
53  }
54  rng.first = first;
55  }
56  }
57 
58  template<char... keys, typename Range>
59  DAW_ATTRIBUTE_FLATTEN static constexpr void move_to_next_of( Range &rng ) {
60  static_assert( sizeof...( keys ) <= 16 );
61 
62  if constexpr( not std::is_same_v<typename Range::exec_tag_t,
64  rng.first =
65  json_details::mem_move_to_next_of<Range::is_unchecked_input, keys...>(
66  Range::exec_tag, rng.first, rng.last );
67  } else {
68  char const *first = rng.first;
69  char const *const last = rng.last;
70  daw_json_assert_weak( first < last, ErrorReason::UnexpectedEndOfData,
71  rng );
72  while( not parse_policy_details::in<keys...>( *first ) ) {
73  ++first;
74  daw_json_assert_weak( first < last, ErrorReason::UnexpectedEndOfData,
75  rng );
76  }
77  rng.first = first;
78  }
79  }
80 
81  DAW_ATTRIBUTE_FLATTEN static constexpr bool is_literal_end( char c ) {
82  return c == '\0' or c == ',' or c == ']' or c == '}';
83  }
84 
85  template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
86  typename Range>
87  DAW_ATTRIBUTE_FLATTEN static constexpr Range
89  // Not checking for Left as it is required to be skipped already
90  auto result = rng;
91  std::size_t cnt = 0;
92  std::uint32_t prime_bracket_count = 1;
93  std::uint32_t second_bracket_count = 0;
94  char const *ptr_first = rng.first;
95  char const *const ptr_last = rng.last;
96 
97  if( DAW_JSON_UNLIKELY( ptr_first >= ptr_last ) ) {
98  return result;
99  }
100  if( *ptr_first == PrimLeft ) {
101  ++ptr_first;
102  }
103  while( DAW_JSON_LIKELY( ptr_first < ptr_last ) ) {
104  switch( *ptr_first ) {
105  case '\\':
106  ++ptr_first;
107  break;
108  case '"':
109  ++ptr_first;
110  if constexpr( not std::is_same_v<typename Range::exec_tag_t,
111  constexpr_exec_tag> ) {
112  ptr_first = json_details::mem_skip_until_end_of_string<
113  Range::is_unchecked_input>( Range::exec_tag, ptr_first,
114  rng.last );
115  } else {
116  while( DAW_JSON_LIKELY( ptr_first < ptr_last ) and
117  *ptr_first != '"' ) {
118  if( *ptr_first == '\\' ) {
119  if( ptr_first + 1 < ptr_last ) {
120  ptr_first += 2;
121  continue;
122  } else {
123  ptr_first = ptr_last;
124  break;
125  }
126  }
127  ++ptr_first;
128  }
129  }
130  daw_json_assert( ptr_first < ptr_last and *ptr_first == '"',
131  ErrorReason::UnexpectedEndOfData, rng );
132  break;
133  case ',':
134  if( DAW_JSON_UNLIKELY( ( prime_bracket_count == 1 ) &
135  ( second_bracket_count == 0 ) ) ) {
136  ++cnt;
137  }
138  break;
139  case PrimLeft:
140  ++prime_bracket_count;
141  break;
142  case PrimRight:
143  --prime_bracket_count;
144  if( prime_bracket_count == 0 ) {
145  ++ptr_first;
146  daw_json_assert( second_bracket_count == 0,
147  ErrorReason::InvalidBracketing, rng );
148  result.last = ptr_first;
149  result.counter = cnt;
150  rng.first = ptr_first;
151  return result;
152  }
153  break;
154  case SecLeft:
155  ++second_bracket_count;
156  break;
157  case SecRight:
158  --second_bracket_count;
159  break;
160  }
161  ++ptr_first;
162  }
163  daw_json_assert( ( prime_bracket_count == 0 ) &
164  ( second_bracket_count == 0 ),
165  ErrorReason::InvalidBracketing, rng );
166  // We include the close primary bracket in the range so that subsequent
167  // parsers have a terminator inside their range
168  result.last = ptr_first;
169  result.counter = cnt;
170  rng.first = ptr_first;
171  return result;
172  }
173 
174  template<char PrimLeft, char PrimRight, char SecLeft, char SecRight,
175  typename Range>
176  DAW_ATTRIBUTE_FLATTEN static constexpr Range
178  // Not checking for Left as it is required to be skipped already
179  auto result = rng;
180  std::size_t cnt = 0;
181  std::uint32_t prime_bracket_count = 1;
182  std::uint32_t second_bracket_count = 0;
183  char const *ptr_first = rng.first;
184 
185  if( *ptr_first == PrimLeft ) {
186  ++ptr_first;
187  }
188  while( true ) {
189  switch( *ptr_first ) {
190  case '\\':
191  ++ptr_first;
192  break;
193  case '"':
194  ++ptr_first;
195  if constexpr( not std::is_same_v<typename Range::exec_tag_t,
196  constexpr_exec_tag> ) {
197  ptr_first = json_details::mem_skip_until_end_of_string<
198  Range::is_unchecked_input>( Range::exec_tag, ptr_first,
199  rng.last );
200  } else {
201  while( *ptr_first != '"' ) {
202  if( *ptr_first == '\\' ) {
203  ++ptr_first;
204  }
205  ++ptr_first;
206  }
207  }
208  break;
209  case ',':
210  if( DAW_JSON_UNLIKELY( ( prime_bracket_count == 1 ) &
211  ( second_bracket_count == 0 ) ) ) {
212  ++cnt;
213  }
214  break;
215  case PrimLeft:
216  ++prime_bracket_count;
217  break;
218  case PrimRight:
219  --prime_bracket_count;
220  if( prime_bracket_count == 0 ) {
221  ++ptr_first;
222  // We include the close primary bracket in the range so that
223  // subsequent parsers have a terminator inside their range
224  result.last = ptr_first;
225  result.counter = cnt;
226  rng.first = ptr_first;
227  return result;
228  }
229  break;
230  case SecLeft:
231  ++second_bracket_count;
232  break;
233  case SecRight:
234  --second_bracket_count;
235  break;
236  }
237  ++ptr_first;
238  }
239  // Should never get here, only loop exit is when PrimaryRight is found and
240  // count == 0
241  DAW_UNREACHABLE( );
242  }
243  };
244 
246 } // namespace daw::json
daw::json::BasicNoCommentSkippingPolicy::skip_bracketed_item_checked
static constexpr DAW_ATTRIBUTE_FLATTEN Range skip_bracketed_item_checked(Range &rng)
Definition: daw_json_parse_policy_no_comments.h:88
daw::json::BasicNoCommentSkippingPolicy::is_literal_end
static constexpr DAW_ATTRIBUTE_FLATTEN bool is_literal_end(char c)
Definition: daw_json_parse_policy_no_comments.h:81
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_UNLIKELY
#define DAW_JSON_UNLIKELY(Bool)
Definition: daw_json_assert.h:35
daw::json::BasicNoCommentSkippingPolicy::move_to_next_of
static constexpr DAW_ATTRIBUTE_FLATTEN void move_to_next_of(Range &rng)
Definition: daw_json_parse_policy_no_comments.h:59
daw_json_parse_common.h
daw::json::BasicNoCommentSkippingPolicy::trim_left_checked
static constexpr DAW_ATTRIBUTE_FLATTEN void trim_left_checked(Range &rng)
Definition: daw_json_parse_policy_no_comments.h:33
daw::json::BasicNoCommentSkippingPolicy::trim_left_unchecked
static constexpr DAW_ATTRIBUTE_FLATTEN void trim_left_unchecked(Range &rng)
Definition: daw_json_parse_policy_no_comments.h:48
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::BasicNoCommentSkippingPolicy
Definition: daw_json_parse_policy_no_comments.h:26
daw::json::BasicNoCommentSkippingPolicy::document_is_minified
static constexpr bool document_is_minified
Definition: daw_json_parse_policy_no_comments.h:30
daw::json::BasicNoCommentSkippingPolicy::skip_bracketed_item_unchecked
static constexpr DAW_ATTRIBUTE_FLATTEN Range skip_bracketed_item_unchecked(Range &rng)
Definition: daw_json_parse_policy_no_comments.h:177