DAW JSON Link
Loading...
Searching...
No Matches
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
12
17
18#include <daw/daw_attributes.h>
19#include <daw/daw_constant.h>
20#include <daw/daw_likely.h>
21#include <daw/daw_not_null.h>
22#include <daw/daw_traits.h>
23
24#include <cstddef>
25#include <cstdint>
26#include <type_traits>
27
28namespace daw::json {
29 inline namespace DAW_JSON_VER {
31 template<typename ParseState>
32 DAW_ATTRIB_FLATINLINE static constexpr void
33 skip_comments_unchecked( ParseState &parse_state ) {
34 while( parse_state.front( ) == '#' ) {
35 parse_state.remove_prefix( );
36 parse_state.template move_to_next_of_unchecked<'\n'>( );
37 parse_state.remove_prefix( );
38 }
39 }
40
41 template<typename ParseState>
42 DAW_ATTRIB_FLATINLINE static constexpr void
43 skip_comments_checked( ParseState &parse_state ) {
44 while( parse_state.has_more( ) and parse_state.front( ) == '#' ) {
45 parse_state.remove_prefix( );
46 parse_state.template move_to_next_of_checked<'\n'>( );
47 // The last line may not end with a newline
48 if( ( ParseState::is_zero_terminated_string or
49 parse_state.has_more( ) ) and
50 parse_state.front( ) == '\n' ) {
51 parse_state.remove_prefix( );
52 }
53 }
54 }
55
56 template<typename ParseState>
57 DAW_ATTRIB_FLATINLINE static constexpr void
58 skip_comments( ParseState &parse_state ) {
59 if constexpr( ParseState::is_unchecked_input ) {
60 skip_comments_unchecked( parse_state );
61 } else {
62 skip_comments_checked( parse_state );
63 }
64 }
65
66 public:
67 template<typename ParseState>
68 DAW_ATTRIB_FLATINLINE static constexpr void
69 trim_left_checked( ParseState &parse_state ) {
70 skip_comments_checked( parse_state );
71 while( parse_state.has_more( ) and parse_state.is_space_unchecked( ) ) {
72 parse_state.remove_prefix( );
73 skip_comments_checked( parse_state );
74 }
75 }
76
77 template<typename ParseState>
78 DAW_ATTRIB_FLATINLINE static constexpr void
79 trim_left_unchecked( ParseState &parse_state ) {
80 skip_comments_unchecked( parse_state );
81 while( parse_state.is_space_unchecked( ) ) {
82 parse_state.remove_prefix( );
83 // Comments can follow whitespace
84 skip_comments_unchecked( parse_state );
85 }
86 }
87
88 template<typename ParseState>
89 DAW_ATTRIB_FLATINLINE static constexpr void
90 move_next_member_unchecked( ParseState &parse_state ) {
91 parse_state.move_next_member_or_end_unchecked( );
92 }
93
94 template<char... keys, typename ParseState>
95 DAW_ATTRIB_FLATINLINE static constexpr void
96 move_to_next_of( ParseState &parse_state ) {
97 skip_comments( parse_state );
98 while( true ) {
99 // Check before reading front( ), skip_comments can reach the end
100 daw_json_assert_weak( parse_state.has_more( ),
101 ErrorReason::UnexpectedEndOfData,
102 parse_state );
103 if( parse_policy_details::in<keys...>( parse_state.front( ) ) ) {
104 break;
105 }
106 parse_state.remove_prefix( );
107 skip_comments( parse_state );
108 }
109 }
110
111 DAW_ATTRIB_FLATINLINE static constexpr bool is_literal_end( char c ) {
112 return c == '\0' or c == ',' or c == ']' or c == '}' or c == '#';
113 }
114
115 template<json_details::SkipBracketedType BracketedType,
116 typename ParseState>
117 DAW_ATTRIB_FLATINLINE static constexpr ParseState
118 skip_bracketed_item_checked( ParseState &parse_state ) {
119 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
120 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
121 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
122 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
123 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
124
125 // Not checking for Left as it is required to be skipped already
126 auto result = parse_state;
127 std::size_t cnt = 0;
128 std::uint32_t prime_bracket_count = 1;
129 std::uint32_t second_bracket_count = 0;
130 auto ptr_first = parse_state.first;
131 auto const ptr_last = parse_state.last;
132 // A null range is a logic error, not bad input
133 daw_json_dbg_ensure( ptr_first != nullptr and ptr_last != nullptr,
134 ErrorReason::InvalidNull );
135 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
136 return result;
137 }
138 if( *ptr_first == PrimLeft ) {
139 ++ptr_first;
140 }
141 while( DAW_LIKELY( ptr_first < ptr_last ) ) {
142 // TODO: use if/else if or put switch into IILE
143 switch( *ptr_first ) {
144 case '\\':
145 ++ptr_first;
146 break;
147 case '"':
148 ++ptr_first;
149 // ptr_first is past an opening quote, so it is not null
150 ptr_first += json_details::mem_skip_until_end_of_string<
151 ParseState::is_unchecked_input,
152 typename ParseState::exec_tag_t>(
153 daw::not_null<char const *>( daw::never_null, ptr_first ),
154 daw::not_null<char const *>( daw::never_null, ptr_last ) )
155 .get( ) -
156 ptr_first;
157 daw_json_ensure( ptr_first < ptr_last,
158 ErrorReason::UnexpectedEndOfData,
159 parse_state );
160 break;
161 case ',':
162 if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
163 ++cnt;
164 }
165 break;
166 case PrimLeft:
167 ++prime_bracket_count;
168 break;
169 case PrimRight::value:
170 --prime_bracket_count;
171 if( prime_bracket_count == 0 ) {
172 daw_json_ensure( second_bracket_count == 0,
173 ErrorReason::InvalidBracketing,
174 parse_state );
175 ++ptr_first;
176 // We include the close primary bracket in the range so that
177 // subsequent parsers have a terminator inside their range
178 result.last = ptr_first;
179 result.counter = cnt;
180 parse_state.first = ptr_first;
181 return result;
182 }
183 break;
184 case SecLeft::value:
185 ++second_bracket_count;
186 break;
187 case SecRight::value:
188 --second_bracket_count;
189 break;
190 case '#':
191 ++ptr_first;
192 while( ptr_first < ptr_last and *ptr_first != '\n' ) {
193 ++ptr_first;
194 }
195 if( ptr_first < ptr_last ) {
196 continue;
197 }
198 break;
199 }
200 ++ptr_first;
201 }
202 daw_json_ensure( ( prime_bracket_count == 0 ) &
203 ( second_bracket_count == 0 ),
204 ErrorReason::InvalidBracketing,
205 parse_state );
206 // We include the close primary bracket in the range so that subsequent
207 // parsers have a terminator inside their range
208 result.last = ptr_first;
209 result.counter = cnt;
210 parse_state.first = ptr_first;
211 return result;
212 }
213
214 template<json_details::SkipBracketedType BracketedType,
215 typename ParseState>
216 DAW_ATTRIB_FLATINLINE static constexpr ParseState
217 skip_bracketed_item_unchecked( ParseState &parse_state ) {
218 DAW_CPP23_STATIC_LOCAL constexpr char PrimLeft =
219 BracketedType == json_details::SkipBracketedType::Class ? '{' : '[';
220 // Not checking for Left as it is required to be skipped already
221 using PrimRight = daw::constant<PrimLeft == '{' ? '}' : ']'>;
222 using SecLeft = daw::constant<PrimLeft == '{' ? '[' : '{'>;
223 using SecRight = daw::constant<SecLeft::value == '{' ? '}' : ']'>;
224
225 auto result = parse_state;
226 std::size_t cnt = 0;
227 std::uint32_t prime_bracket_count = 1;
228 std::uint32_t second_bracket_count = 0;
229 auto ptr_first = parse_state.first;
230 auto const ptr_last = parse_state.last;
231 // A null range is a logic error, not bad input
232 daw_json_dbg_ensure( ptr_first != nullptr and ptr_last != nullptr,
233 ErrorReason::InvalidNull );
234 if( *ptr_first == PrimLeft ) {
235 ++ptr_first;
236 }
237 while( true ) {
238 switch( *ptr_first ) {
239 case '\\':
240 ++ptr_first;
241 break;
242 case '"':
243 ++ptr_first;
244
245 // ptr_first is past an opening quote, so it is not null
246 ptr_first += json_details::mem_skip_until_end_of_string<
247 ParseState::is_unchecked_input,
248 typename ParseState::exec_tag_t>(
249 daw::not_null<char const *>( daw::never_null, ptr_first ),
250 daw::not_null<char const *>( daw::never_null, ptr_last ) )
251 .get( ) -
252 ptr_first;
253 break;
254 case ',':
255 if( prime_bracket_count == 1 and second_bracket_count == 0 ) {
256 ++cnt;
257 }
258 break;
259 case PrimLeft:
260 ++prime_bracket_count;
261 break;
262 case PrimRight::value:
263 --prime_bracket_count;
264 if( prime_bracket_count == 0 ) {
265 ++ptr_first;
266 // We include the close primary bracket in the range so that
267 // subsequent parsers have a terminator inside their range
268 result.last = ptr_first;
269 result.counter = cnt;
270 parse_state.first = ptr_first;
271 return result;
272 }
273 break;
274 case SecLeft::value:
275 ++second_bracket_count;
276 break;
277 case SecRight::value:
278 --second_bracket_count;
279 break;
280 case '#':
281 ++ptr_first;
282 while( *ptr_first != '\n' ) {
283 ++ptr_first;
284 }
285 break;
286 }
287 ++ptr_first;
288 }
289 DAW_UNREACHABLE( );
290 }
291 };
292 } // namespace DAW_JSON_VER
293} // 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.
constexpr decltype(auto) get(basic_json_pair< PolicyFlags, Allocator > const &parse_state)
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20