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 = daw::not_null<char const *>( parse_state.first );
39 auto const last = daw::not_null<char const *>( 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
66 trim_left_unchecked( ParseState &parse_state ) {
67 if constexpr( not ParseState::minified_document ) {
68 auto first =
69 daw::not_null<char const *>( daw::never_null, parse_state.first );
70 while( DAW_UNLIKELY(
71 ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
72 1U ) <= 0x1F ) ) {
73
74 ++first;
75 }
76 parse_state.first = first;
77 }
78 }
79
80 template<typename ParseState>
81 DAW_ATTRIB_FLATINLINE static constexpr void
82 move_next_member_unchecked( ParseState &parse_state ) {
83 auto pf = daw::not_null( daw::never_null, parse_state.first );
84 auto pl = daw::not_null( daw::never_null, parse_state.last );
85 parse_state.first =
86 json_details::memchr_unchecked<'"',
87 typename ParseState::exec_tag_t,
88 ParseState::expect_long_strings>( pf,
89 pl );
90 }
91
92 template<char... keys, typename ParseState>
93 DAW_ATTRIB_FLATINLINE static constexpr void
94 move_to_next_of( ParseState &parse_state ) {
95 static_assert( sizeof...( keys ) > 0 );
96 static_assert( sizeof...( keys ) <= 16 );
97
98 if( not json_details::use_constexpr_exec_mode<
99 typename ParseState::exec_tag_t>( ) ) {
100 auto pf = daw::not_null<char const *>{ parse_state.first };
101 auto pl = daw::not_null<char const *>{ parse_state.last };
102 parse_state.first =
103 json_details::mempbrk<ParseState::is_unchecked_input,
104 typename ParseState::exec_tag_t,
105 ParseState::expect_long_strings,
106 keys...>( pf, pl );
107 } else {
108 auto first = daw::not_null<char const *>( parse_state.first );
109 auto const last = daw::not_null<char const *>( 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 }
123 *first != '\0', ErrorReason::UnexpectedEndOfData, 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_INLINE static constexpr bool is_literal_end( char c ) {
138 return ( c == '\0' ) | ( c == ',' ) | ( c == ']' ) | ( c == '}' );
139 }
140
141 template<json_details::SkipBracketedType BracketedType,
142 typename ParseState>
143 DAW_ATTRIB_FLATTEN static constexpr ParseState
144 skip_bracketed_item_checked( ParseState &parse_state ) {
145 constexpr char PrimLeft =
146 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
147 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
148 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
149 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
150
151 // Not checking for Left as it is required to be skipped already
152 auto ptr_first = daw::not_null<char const *>( parse_state.first );
153 auto const ptr_last = daw::not_null<char const *>( parse_state.last );
154 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
155 return parse_state;
156 }
157 auto result = parse_state;
158 std::size_t cnt = 0;
159 std::uint32_t prime_bracket_count = 1;
160 std::uint32_t second_bracket_count = 0;
161
162 if( *ptr_first == PrimLeft ) {
163 ++ptr_first;
164 }
165 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
166 switch( *ptr_first ) {
167 case '\\':
168 ++ptr_first;
169 break;
170 case '"':
171 ++ptr_first;
172 ptr_first = json_details::mem_skip_until_end_of_string<
173 ParseState::is_unchecked_input,
174 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
175 daw_json_ensure( ptr_first < ptr_last and *ptr_first == '"',
176 ErrorReason::UnexpectedEndOfData,
177 parse_state );
178 break;
179 case ',':
180 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
181 ( second_bracket_count == 0 ) ) ) {
182 ++cnt;
183 }
184 break;
185 case PrimLeft:
186 ++prime_bracket_count;
187 break;
188 case PrimRight::value:
189 --prime_bracket_count;
190 if( prime_bracket_count == 0 ) {
191 ++ptr_first;
192 daw_json_ensure( second_bracket_count == 0,
193 ErrorReason::InvalidBracketing,
194 parse_state );
195 result.last = ptr_first;
196 result.counter = cnt;
197 parse_state.first = ptr_first;
198 return result;
199 }
200 break;
201 case SecLeft::value:
202 ++second_bracket_count;
203 break;
204 case SecRight::value:
205 --second_bracket_count;
206 break;
207 }
208 ++ptr_first;
209 }
210 daw_json_ensure( ( prime_bracket_count == 0 ) &
211 ( second_bracket_count == 0 ),
212 ErrorReason::InvalidBracketing,
213 parse_state );
214 // We include the close primary bracket in the range so that subsequent
215 // parsers have a terminator inside their range
216 result.last = ptr_first;
217 result.counter = cnt;
218 parse_state.first = ptr_first;
219 return result;
220 }
221
222 template<json_details::SkipBracketedType BracketedType,
223 typename ParseState>
224 DAW_ATTRIB_NOINLINE static constexpr ParseState
225 skip_bracketed_item_unchecked( ParseState &parse_state ) {
226 constexpr char PrimLeft =
227 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
228 // Not checking for Left as it is required to be skipped already
229 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
230 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
231 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
232
233 auto result = parse_state;
234 std::size_t cnt = 0;
235 std::uint32_t prime_bracket_count = 1;
236 std::uint32_t second_bracket_count = 0;
237 auto ptr_first = daw::not_null<char const *>( parse_state.first );
238 auto const ptr_last = daw::not_null<char const *>( parse_state.last );
239
240 if( *ptr_first == PrimLeft ) {
241 ++ptr_first;
242 }
243 while( true ) {
244 switch( *ptr_first ) {
245 case '\\':
246 ++ptr_first;
247 break;
248 case '"':
249 ++ptr_first;
250 ptr_first = json_details::mem_skip_until_end_of_string<
251 ParseState::is_unchecked_input,
252 typename ParseState::exec_tag_t>( ptr_first, ptr_last );
253 break;
254 case ',':
255 if( DAW_UNLIKELY( ( prime_bracket_count == 1 ) &
256 ( second_bracket_count == 0 ) ) ) {
257 ++cnt;
258 }
259 break;
260 case PrimLeft:
261 ++prime_bracket_count;
262 break;
263 case PrimRight::value:
264 --prime_bracket_count;
265 if( prime_bracket_count == 0 ) {
266 ++ptr_first;
267 // We include the close primary bracket in the range so that
268 // subsequent parsers have a terminator inside their range
269 result.last = ptr_first;
270 result.counter = cnt;
271 parse_state.first = ptr_first;
272 return result;
273 }
274 break;
275 case SecLeft::value:
276 ++second_bracket_count;
277 break;
278 case SecRight::value:
279 --second_bracket_count;
280 break;
281 }
282 ++ptr_first;
283 }
284 // Should never get here, only loop exit is when PrimaryRight is found
285 // and count == 0
286 DAW_UNREACHABLE( );
287 }
288 };
289 } // namespace DAW_JSON_VER
290} // 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.
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