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