DAW JSON Link
Loading...
Searching...
No Matches
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
12
18
19#include <daw/daw_attributes.h>
20#include <daw/daw_constant.h>
21#include <daw/daw_function_table.h>
22#include <daw/daw_likely.h>
23#include <daw/daw_not_null.h>
24#include <daw/daw_traits.h>
25
26#include <cstddef>
27#include <cstdint>
28#include <type_traits>
29
30namespace daw::json {
31 inline namespace DAW_JSON_VER {
33 template<typename ParseState>
34 DAW_ATTRIB_FLATINLINE static constexpr void
35 trim_left_checked( ParseState &parse_state ) {
36 if constexpr( not ParseState::minified_document ) {
37 // SIMD here was much slower, most JSON has very minimal whitespace
38 auto first = parse_state.first;
39 auto const last = parse_state.last;
40 // A null range is a logic error, not bad input
41 daw_json_dbg_ensure( first != nullptr and last != nullptr,
42 ErrorReason::InvalidNull );
43
44 // only used when not zero terminated string and gcc9 warns
45 (void)last;
46
47 if constexpr( ParseState::is_zero_terminated_string ) {
48 // Ensure that zero terminator isn't included in skipable value
49 while( DAW_UNLIKELY(
50 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
51 1U ) <= 0x1FU ) ) {
52
53 ++first;
54 }
55 } else {
56 while(
57 DAW_LIKELY( first < last ) and
58 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
59 1U ) <= 0x1FU ) {
60 ++first;
61 }
62 }
63 parse_state.first = first;
64 }
65 }
66
67 template<typename ParseState>
68 DAW_ATTRIB_FLATINLINE static constexpr void
69 trim_left_unchecked( ParseState &parse_state ) {
70 if constexpr( not ParseState::minified_document ) {
71 auto first = parse_state.first;
72 // A null range is a logic error, not bad input
73 daw_json_dbg_ensure( first != nullptr, ErrorReason::InvalidNull );
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 auto pf = daw::not_null<char const *>( daw::never_null, parse_state.first );
88 auto pl = daw::not_null<char const *>( daw::never_null, parse_state.last );
89 auto const position =
90 json_details::memchr_unchecked<'"',
91 typename ParseState::exec_tag_t,
92 ParseState::expect_long_strings>( pf,
93 pl );
94 parse_state.first = json_details::input_pointer( parse_state.first, position.get( ) );
95 }
96
97 template<char... keys, typename ParseState>
98 DAW_ATTRIB_FLATINLINE static constexpr void
99 move_to_next_of( ParseState &parse_state ) {
100 static_assert( sizeof...( keys ) > 0 );
101 static_assert( sizeof...( keys ) <= 16 );
102
103 if( not json_details::use_constexpr_exec_mode<
104 typename ParseState::exec_tag_t>( ) ) {
105 auto pf = daw::not_null<char const *>{ parse_state.first };
106 auto pl = daw::not_null<char const *>{ parse_state.last };
107 auto const position =
108 json_details::mempbrk<ParseState::is_unchecked_input,
109 typename ParseState::exec_tag_t,
110 ParseState::expect_long_strings,
111 keys...>( pf, pl );
112 parse_state.first = json_details::input_pointer( parse_state.first, position.get( ) );
113 } else {
114 auto first = daw::not_null<char const *>( parse_state.first );
115 auto const last = daw::not_null<char const *>( parse_state.last );
116
117 // silencing gcc9 unused warning. last is used inside if constexpr
118 // blocks
119 (void)last;
120
121 if( ParseState::is_zero_terminated_string ) {
122 daw_json_assert_weak( first < last and *first != '\0',
123 ErrorReason::UnexpectedEndOfData,
124 parse_state );
125 while( not parse_policy_details::in<keys...>( *first ) ) {
126 ++first;
127 }
129 *first != '\0', ErrorReason::UnexpectedEndOfData, parse_state );
130 } else {
132 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
133 while( not parse_policy_details::in<keys...>( *first ) ) {
134 ++first;
136 first < last, ErrorReason::UnexpectedEndOfData, parse_state );
137 }
138 }
139 parse_state.first = json_details::input_pointer( parse_state.first, first.get( ) );
140 }
141 }
142
143 DAW_ATTRIB_INLINE static constexpr bool is_literal_end( char c ) {
144 return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
145 }
146
147 template<json_details::SkipBracketedType BracketedType,
148 typename ParseState>
149 DAW_ATTRIB_FLATTEN static constexpr ParseState
150 skip_bracketed_item_checked( ParseState &parse_state ) {
151 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
152 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
153 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
154 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
155 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
156
157 // Not checking for Left as it is required to be skipped already
158 char const *ptr_first = parse_state.first;
159 char const *const ptr_last = parse_state.last;
160 // A null range is a logic error, not bad input
161 daw_json_dbg_ensure( ptr_first != nullptr and ptr_last != nullptr,
162 ErrorReason::InvalidNull );
163 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
164 return parse_state;
165 }
166 auto result = parse_state;
167 std::size_t cnt = 0;
168 std::uint32_t prime_bracket_count = 1;
169 std::uint32_t second_bracket_count = 0;
170
171 if( *ptr_first == PrimLeft ) {
172 ++ptr_first;
173 }
174 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
175 switch( *ptr_first ) {
176 case '\\':
177 ++ptr_first;
178 break;
179 case '"':
180 ++ptr_first;
181 ptr_first = json_details::mem_skip_until_end_of_string<
182 ParseState::is_unchecked_input,
183 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
184 daw_json_ensure( ptr_first < ptr_last and *ptr_first == '"',
185 ErrorReason::UnexpectedEndOfData,
186 parse_state );
187 break;
188 case ',':
189 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
190 ( second_bracket_count == 0 ) ) ) {
191 ++cnt;
192 }
193 break;
194 case PrimLeft:
195 ++prime_bracket_count;
196 break;
197 case PrimRight::value:
198 --prime_bracket_count;
199 if( prime_bracket_count == 0 ) {
200 ++ptr_first;
201 daw_json_ensure( second_bracket_count == 0,
202 ErrorReason::InvalidBracketing,
203 parse_state );
204 result.last = json_details::input_pointer( result.first, ptr_first );
205 result.counter = cnt;
206 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first );
207 return result;
208 }
209 break;
210 case SecLeft::value:
211 ++second_bracket_count;
212 break;
213 case SecRight::value:
214 --second_bracket_count;
215 break;
216 }
217 ++ptr_first;
218 }
219 daw_json_ensure( ( prime_bracket_count == 0 ) &
220 ( second_bracket_count == 0 ),
221 ErrorReason::InvalidBracketing,
222 parse_state );
223 // We include the close primary bracket in the range so that subsequent
224 // parsers have a terminator inside their range
225 result.last = json_details::input_pointer( result.first, ptr_first );
226 result.counter = cnt;
227 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first );
228 return result;
229 }
230
231 template<json_details::SkipBracketedType BracketedType,
232 typename ParseState>
233 DAW_ATTRIB_NOINLINE static constexpr ParseState
234 skip_bracketed_item_unchecked( ParseState &parse_state ) {
235 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
236 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
237 // Not checking for Left as it is required to be skipped already
238 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
239 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
240 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
241
242 auto result = parse_state;
243 std::size_t cnt = 0;
244 std::uint32_t prime_bracket_count = 1;
245 std::uint32_t second_bracket_count = 0;
246 char const *ptr_first = parse_state.first;
247 char const *const ptr_last = parse_state.last;
248 // A null range is a logic error, not bad input
249 daw_json_dbg_ensure( ptr_first != nullptr and ptr_last != nullptr,
250 ErrorReason::InvalidNull );
251
252 if( *ptr_first == PrimLeft ) {
253 ++ptr_first;
254 }
255 while( true ) {
256 switch( *ptr_first ) {
257 case '\\':
258 ++ptr_first;
259 break;
260 case '"':
261 ++ptr_first;
262 ptr_first = json_details::mem_skip_until_end_of_string<
263 ParseState::is_unchecked_input,
264 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
265 break;
266 case ',':
267 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
268 ( second_bracket_count == 0 ) ) ) {
269 ++cnt;
270 }
271 break;
272 case PrimLeft:
273 ++prime_bracket_count;
274 break;
275 case PrimRight::value:
276 --prime_bracket_count;
277 if( prime_bracket_count == 0 ) {
278 ++ptr_first;
279 // We include the close primary bracket in the range so that
280 // subsequent parsers have a terminator inside their range
281 result.last = json_details::input_pointer( result.first, ptr_first );
282 result.counter = cnt;
283 parse_state.first = json_details::input_pointer( parse_state.first, ptr_first );
284 return result;
285 }
286 break;
287 case SecLeft::value:
288 ++second_bracket_count;
289 break;
290 case SecRight::value:
291 --second_bracket_count;
292 break;
293 }
294 ++ptr_first;
295 }
296 // Should never get here, only loop exit is when PrimaryRight is found
297 // and count == 0
298 DAW_UNREACHABLE( );
299 }
300 };
301 } // namespace DAW_JSON_VER
302} // namespace daw::json
#define daw_json_dbg_ensure(Bool,...)
#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.
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
static DAW_ATTRIB_NOINLINE constexpr 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:20