DAW JSON Link
Loading...
Searching...
No Matches
daw_json_iterator.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
16
17#include <daw/daw_cxmath.h>
18#include <daw/daw_move.h>
19#include <daw/daw_string_view.h>
20#include <daw/daw_traits.h>
21#include <daw/daw_utility.h>
22
23#include <array>
24#include <cstddef>
25#include <cstdlib>
26#include <iterator>
27#include <limits>
28#include <optional>
29#include <string>
30#include <type_traits>
31
32namespace daw::json {
33 inline namespace DAW_JSON_VER {
34 namespace json_details {
35 template<typename T>
36 struct assign_on_dtor {
37 T &lhs;
38 T const &rhs;
39
40 DAW_ATTRIB_INLINE constexpr assign_on_dtor( T &Lhs,
41 T const &Rhs ) noexcept
42 : lhs( Lhs )
43 , rhs( Rhs ) {}
44
45 DAW_ATTRIB_INLINE DAW_JSON_CPP20_CX_DTOR ~assign_on_dtor( ) noexcept {
46 lhs = rhs;
47 }
48 };
49
50 template<typename T>
51 assign_on_dtor( T const &, T const & ) -> assign_on_dtor<T>;
52
53 template<typename ParseState>
54 [[nodiscard]] constexpr zstring_policy_t<ParseState>
55 to_zstring_state( ParseState const &state ) {
56 return zstring_policy_t<ParseState>( state.first,
57 state.last,
58 state.class_first,
59 state.class_last,
60 state.counter );
61 }
62 } // namespace json_details
63 /***
64 * Iterator for iterating over JSON array's
65 * @tparam JsonElement type under underlying element in array. If
66 * heterogeneous, a basic_json_value_iterator may be more appropriate
67 * @note An exception from dereferencing or incrementing invalidates the
68 * iterator. Before using it again, restore it by assigning a valid copy
69 * saved before the operation that threw. Incrementing an invalidated
70 * iterator is not a supported way to recover from a parsing error.
71 * @tparam ParseState Parsing policy type
72 */
73 template<typename JsonElement, typename ParseState, typename = void>
75
76 static constexpr ParseState get_range( daw::string_view data,
77 daw::string_view member_path ) {
78 auto [result, is_found] = json_details::find_range<ParseState>(
79 data, { std::data( member_path ), std::size( member_path ) } );
80 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
82 result.front( ) == '[', ErrorReason::InvalidArrayStart, result );
83 return result;
84 }
85
86 public:
87 using element_type = json_details::json_deduced_type<JsonElement>;
88 static_assert( not std::is_same_v<element_type, void>,
89 "Unknown JsonElement type." );
90 using value_type = json_details::json_result_t<element_type>;
92 using pointer = json_details::arrow_proxy<value_type>;
93 using difference_type = std::ptrdiff_t;
94 // Can do forward iteration and be stored
95 using iterator_category = std::input_iterator_tag;
96
97 private:
98 ParseState m_state = ParseState( );
99 /***
100 * This lets us fastpath and just skip n characters as we have already
101 * parsed them
102 */
103 mutable char const *m_can_skip = nullptr;
104
105 static constexpr bool can_use_zstring =
106 json_details::can_use_runtime_zstring_v<ParseState, daw::string_view>;
107
109 bool m_is_zstring = false;
110
111 template<typename State>
112 [[nodiscard]] constexpr value_type parse_current( State tmp ) const {
113 auto const run_after_parse =
114 json_details::assign_on_dtor{ m_can_skip, tmp.first };
115 (void)run_after_parse;
116 return json_details::
117 parse_value<element_type, false, element_type::expected_type>( tmp );
118 }
119
120 public:
121 explicit json_array_iterator_t( ) = default;
122
123 explicit constexpr json_array_iterator_t( daw::string_view jd )
124 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) )
125 , m_is_zstring( json_details::is_runtime_zstring<ParseState>( jd ) ) {
126
127 m_state.trim_left( );
128 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
129 ErrorReason::InvalidArrayStart,
130 m_state );
131
132 m_state.remove_prefix( );
133 m_state.trim_left( );
135 m_state.has_more( ), ErrorReason::UnexpectedEndOfData, m_state );
136 }
137
138 explicit constexpr json_array_iterator_t( daw::string_view jd,
139 daw::string_view start_path )
140 : m_state( get_range( jd, start_path ) )
141 , m_is_zstring( json_details::is_runtime_zstring<ParseState>( jd ) ) {
142
143 m_state.trim_left( );
144 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
145 ErrorReason::InvalidArrayStart,
146 m_state );
147
148 m_state.remove_prefix( );
149 m_state.trim_left( );
151 m_state.has_more( ), ErrorReason::UnexpectedEndOfData, m_state );
152 }
153
155 constexpr json_array_iterator_t begin( ) const {
156 return *this;
157 }
158
160 constexpr json_array_iterator_t end( ) const {
161 return json_array_iterator_t( );
162 }
163
167 [[nodiscard]] constexpr value_type operator*( ) const {
168 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
169 ErrorReason::UnexpectedEndOfData,
170 m_state );
171
172 if constexpr( can_use_zstring ) {
173 if( m_is_zstring ) {
174 return parse_current( json_details::to_zstring_state( m_state ) );
175 }
176 }
177 return parse_current( m_state );
178 }
179
185 [[nodiscard]] pointer operator->( ) const {
186 return pointer{ operator*( ) };
187 }
188
189 /***
190 * Move the parse state to the next element
191 * @return iterator after moving
192 */
194 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
195 ErrorReason::UnexpectedEndOfData,
196 m_state );
197 if constexpr( can_use_zstring ) {
198 if( m_is_zstring ) {
199 auto state = json_details::to_zstring_state( m_state );
200 move_next( state );
201 m_state.first = state.first;
202 return *this;
203 }
204 }
205 move_next( m_state );
206 return *this;
207 }
208
209 private:
210 template<typename State>
211 constexpr void move_next( State &state ) {
212 if( m_can_skip ) {
213 state.first = m_can_skip;
214 m_can_skip = nullptr;
215 } else {
216 (void)json_details::skip_known_value<element_type>( state );
217 }
218 state.trim_left( );
219 daw_json_assert_weak( state.has_more( ) and
220 state.is_at_next_array_element( ),
221 ErrorReason::UnexpectedEndOfData,
222 state );
223
224 state.move_next_member_or_end( );
225 state.trim_left( );
227 state.has_more( ), ErrorReason::UnexpectedEndOfData, state );
228 }
229
230 public:
231
235 constexpr void operator++( int ) & {
236 (void)operator++( );
237 }
238
239 /***
240 * Is it ok to dereference iterator
241 * @return true when there is parse data available
242 */
243 [[nodiscard]] constexpr bool good( ) const {
244 return not m_state.is_null( ) and m_state.has_more( ) and
245 m_state.front( ) != ']';
246 }
247
250 [[nodiscard]] explicit constexpr operator bool( ) const {
251 return good( );
252 }
253
257 [[nodiscard]] constexpr bool
258 operator==( json_array_iterator_t const &rhs ) const {
259 auto const not_lhs = not( *this );
260 auto const not_rhs = not( rhs );
261 if( not_lhs ) {
262 return not_rhs;
263 }
264 if( not_rhs ) {
265 return false;
266 }
267 return ( m_state.first == rhs.m_state.first );
268 }
269
273 [[nodiscard]] constexpr bool
274 operator!=( json_array_iterator_t const &rhs ) const {
275 if( not( *this ) ) {
276 return static_cast<bool>( rhs );
277 }
278 if( not rhs ) {
279 return true;
280 }
281 return m_state.first != rhs.m_state.first;
282 }
283 };
284
285 template<typename JsonElement, auto... PolicyFlags>
287 JsonElement,
289 options::details::make_parse_flags<PolicyFlags...>( ).value>>>;
298 template<typename JsonElement, auto... PolicyFlags>
301 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
302
303 static constexpr ParseState get_range( daw::string_view data,
304 daw::string_view member_path ) {
305 auto [result, is_found] = json_details::find_range<ParseState>(
306 data, { std::data( member_path ), std::size( member_path ) } );
307 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
309 result.front( ) == '[', ErrorReason::InvalidArrayStart, result );
310 return result;
311 }
312
313 public:
314 using element_type = json_details::json_deduced_type<JsonElement>;
315 static_assert( not std::is_same_v<element_type, void>,
316 "Unknown JsonElement type." );
317 using value_type = json_details::json_result_t<element_type>;
319 using pointer = json_details::arrow_proxy<value_type>;
320 using difference_type = std::ptrdiff_t;
321
322 private:
323 mutable ParseState m_state = ParseState( );
324
325 static constexpr bool can_use_zstring =
326 json_details::can_use_runtime_zstring_v<ParseState, daw::string_view>;
327
329 bool m_is_zstring = false;
330
331 public:
332 explicit json_array_iterator_once( ) = default;
333
334 explicit constexpr json_array_iterator_once( daw::string_view jd )
335 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) )
336 , m_is_zstring( json_details::is_runtime_zstring<ParseState>( jd ) ) {
337
338 m_state.trim_left( );
339 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
340 ErrorReason::InvalidArrayStart,
341 m_state );
342
343 m_state.remove_prefix( );
344 m_state.trim_left( );
346 m_state.has_more( ), ErrorReason::UnexpectedEndOfData, m_state );
347 }
348
349 explicit constexpr json_array_iterator_once( daw::string_view jd,
350 daw::string_view start_path )
351 : m_state( get_range( jd, start_path ) )
352 , m_is_zstring( json_details::is_runtime_zstring<ParseState>( jd ) ) {
353
354 m_state.trim_left( );
355 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
356 ErrorReason::InvalidArrayStart,
357 m_state );
358
359 m_state.remove_prefix( );
360 m_state.trim_left( );
362 m_state.has_more( ), ErrorReason::UnexpectedEndOfData, m_state );
363 }
364
368 [[nodiscard]] constexpr value_type operator*( ) const {
369 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
370 ErrorReason::UnexpectedEndOfData,
371 m_state );
372
373 if constexpr( can_use_zstring ) {
374 if( m_is_zstring ) {
375 auto state = json_details::to_zstring_state( m_state );
376 auto const run_after_parse =
377 json_details::assign_on_dtor{ m_state.first, state.first };
378 (void)run_after_parse;
379 return json_details::
380 parse_value<element_type, false, element_type::expected_type>(
381 state );
382 }
383 }
384 return json_details::
385 parse_value<element_type, false, element_type::expected_type>(
386 m_state );
387 }
388
389 /***
390 * Move the parse state to the next element
391 * @return iterator after moving
392 */
394 daw_json_assert_weak( m_state.has_more( ) and
395 m_state.is_at_next_array_element( ),
396 ErrorReason::UnexpectedEndOfData,
397 m_state );
398 if constexpr( can_use_zstring ) {
399 if( m_is_zstring ) {
400 auto state = json_details::to_zstring_state( m_state );
401 state.move_next_member_or_end( );
402 m_state.first = state.first;
403 } else {
404 m_state.move_next_member_or_end( );
405 }
406 } else {
407 m_state.move_next_member_or_end( );
408 }
410 m_state.has_more( ), ErrorReason::UnexpectedEndOfData, m_state );
411 return *this;
412 }
413
417 constexpr void operator++( int ) & {
418 (void)operator++( );
419 }
420
421 /***
422 * Is it ok to dereference iterator
423 * @return true when there is parse data available
424 */
425 [[nodiscard]] constexpr bool good( ) const {
426 return not m_state.is_null( ) and m_state.has_more( ) and
427 m_state.front( ) != ']';
428 }
429
432 [[nodiscard]] explicit constexpr operator bool( ) const {
433 return good( );
434 }
435
439 [[nodiscard]] constexpr bool
441 auto const not_lhs = not( *this );
442 auto const not_rhs = not( rhs );
443 if( not_lhs ) {
444 return not_rhs;
445 }
446 if( not_rhs ) {
447 return false;
448 }
449 return ( m_state.first == rhs.m_state.first );
450 }
451
455 [[nodiscard]] constexpr bool
457 auto const not_lhs = not( *this );
458 auto const not_rhs = not( rhs );
459 if( not_lhs ) {
460 return not not_rhs;
461 }
462 if( not_rhs ) {
463 return true;
464 }
465 return m_state.first != rhs.m_state.first;
466 }
467 };
468
471 template<typename JsonElement, auto... PolicyFlags>
474 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
475 using iterator = json_array_iterator<JsonElement, PolicyFlags...>;
476
477 private:
478 iterator m_first{ };
479 iterator m_last{ };
480
481 public:
482 explicit json_array_range( ) = default;
483
484 explicit constexpr json_array_range( daw::string_view jd )
485 : m_first( jd ) {}
486
487 explicit constexpr json_array_range( daw::string_view jd,
488 daw::string_view start_path )
489 : m_first( jd, start_path ) {}
490
492 [[nodiscard]] constexpr iterator begin( ) const {
493 return m_first;
494 }
495
497 [[nodiscard]] constexpr iterator end( ) const {
498 return m_last;
499 }
500
503 [[nodiscard]] constexpr bool empty( ) const {
504 return m_first == m_last;
505 }
506 };
507
511 template<typename JsonElement, auto... PolicyFlags>
514 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
515 using iterator = json_array_iterator_once<JsonElement, PolicyFlags...>;
516
517 private:
518 iterator m_first{ };
519 iterator m_last{ };
520
521 public:
523
524 explicit constexpr json_array_range_once( daw::string_view jd )
525 : m_first( jd ) {}
526
527 explicit constexpr json_array_range_once( daw::string_view jd,
528 daw::string_view start_path )
529 : m_first( jd, start_path ) {}
530
532 [[nodiscard]] constexpr iterator begin( ) const {
533 return m_first;
534 }
535
537 [[nodiscard]] constexpr iterator end( ) const {
538 return m_last;
539 }
540
543 [[nodiscard]] constexpr bool empty( ) const {
544 return m_first == m_last;
545 }
546 };
547 } // namespace DAW_JSON_VER
548} // namespace daw::json
Iterator for iterating over JSON arrays. Requires that operator* and operator++ be called in that seq...
constexpr bool operator!=(json_array_iterator_once const &rhs) const
Check if the other iterator is not equivalent.
constexpr void operator++(int) &
Move the parse state to the next element.
static constexpr ParseState get_range(daw::string_view data, daw::string_view member_path)
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParseState
constexpr value_type operator*() const
Parse the current element.
constexpr bool operator==(json_array_iterator_once const &rhs) const
Compare rhs for equivalence.
constexpr json_array_iterator_once(daw::string_view jd, daw::string_view start_path)
constexpr void operator++(int) &
Move the parse state to the next element.
constexpr value_type operator*() const
Parse the current element.
constexpr bool operator==(json_array_iterator_t const &rhs) const
Compare rhs for equivalence.
static constexpr ParseState get_range(daw::string_view data, daw::string_view member_path)
constexpr bool operator!=(json_array_iterator_t const &rhs) const
Check if the other iterator is not equivalent.
pointer operator->() const
A dereferencable value proxy holding the result of operator* This is for compatibility with the Itera...
constexpr json_array_iterator_t(daw::string_view jd, daw::string_view start_path)
#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.
#define DAW_JSON_CPP20_CX_DTOR
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
A range of json_array_iterator_onces. Requires that op*‍/op++ be called in that sequence one time unt...
constexpr json_array_range_once(daw::string_view jd, daw::string_view start_path)
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParsePolicy
constexpr bool empty() const
Are there any elements in range.
constexpr bool empty() const
Are there any elements in range.
constexpr json_array_range(daw::string_view jd, daw::string_view start_path)
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParsePolicy
Handles the bounds and policy items for parsing execution and comments.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20