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
11#include "impl/version.h"
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 } // namespace json_details
54 /***
55 * Iterator for iterating over JSON array's
56 * @tparam JsonElement type under underlying element in array. If
57 * heterogeneous, a basic_json_value_iterator may be more appropriate
58 * @tparam ParsePolicy Parsing policy type
59 */
60 template<typename JsonElement, typename ParseState, typename = void>
62 using CharT = typename ParseState::CharT;
63
64 static constexpr ParseState get_range( daw::string_view data,
65 daw::string_view member_path ) {
66 auto [result, is_found] = json_details::find_range<ParseState>(
67 DAW_FWD( data ),
68 { std::data( member_path ), std::size( member_path ) } );
69 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
70 daw_json_ensure( result.front( ) == '[', ErrorReason::InvalidArrayStart,
71 result );
72 return result;
73 }
74
75 public:
76 using element_type = json_details::json_deduced_type<JsonElement>;
77 static_assert( not std::is_same_v<element_type, void>,
78 "Unknown JsonElement type." );
79 using value_type = json_details::json_result_t<element_type>;
81 using pointer = json_details::arrow_proxy<value_type>;
82 using difference_type = std::ptrdiff_t;
83 // Can do forward iteration and be stored
84 using iterator_category = std::input_iterator_tag;
85
86 private:
87 ParseState m_state = ParseState( );
88 /***
89 * This lets us fastpath and just skip n characters as we have already
90 * parsed them
91 */
92 mutable CharT *m_can_skip = nullptr;
93
94 public:
95 explicit json_array_iterator_t( ) = default;
96
97 explicit constexpr json_array_iterator_t( daw::string_view jd )
98 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) ) {
99
100 m_state.trim_left( );
101 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
102 ErrorReason::InvalidArrayStart, m_state );
103
104 m_state.remove_prefix( );
105 m_state.trim_left( );
106 }
107
108 explicit constexpr json_array_iterator_t( daw::string_view jd,
109 daw::string_view start_path )
110 : m_state( get_range( jd, start_path ) ) {
111
112 m_state.trim_left( );
113 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
114 ErrorReason::InvalidArrayStart, m_state );
115
116 m_state.remove_prefix( );
117 m_state.trim_left( );
118 }
119
121 constexpr json_array_iterator_t begin( ) const {
122 return *this;
123 }
124
126 constexpr json_array_iterator_t end( ) const {
127 return json_array_iterator_t( );
128 }
129
133 [[nodiscard]] constexpr value_type operator*( ) const {
134 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
135 ErrorReason::UnexpectedEndOfData, m_state );
136
137 auto tmp = m_state;
138
139 auto const run_after_parse =
140 json_details::assign_on_dtor{ m_can_skip, tmp.first };
141 (void)run_after_parse;
142 return json_details::parse_value<element_type, false,
143 element_type::expected_type>( tmp );
144 }
145
151 [[nodiscard]] pointer operator->( ) const {
152 return pointer{ operator*( ) };
153 }
154
155 /***
156 * Move the parse state to the next element
157 * @return iterator after moving
158 */
160 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
161 ErrorReason::UnexpectedEndOfData, m_state );
162 if( m_can_skip ) {
163 m_state.first = m_can_skip;
164 m_can_skip = nullptr;
165 } else {
166 (void)json_details::skip_known_value<element_type>( m_state );
167 }
168 m_state.move_next_member_or_end( );
169 return *this;
170 }
171
175 constexpr void operator++( int ) & {
176 (void)operator++( );
177 }
178
179 /***
180 * Is it ok to dereference iterator
181 * @return true when there is parse data available
182 */
183 [[nodiscard]] constexpr bool good( ) const {
184 return not m_state.is_null( ) and m_state.has_more( ) and
185 m_state.front( ) != ']';
186 }
187
190 [[nodiscard]] explicit constexpr operator bool( ) const {
191 return good( );
192 }
193
197 [[nodiscard]] constexpr bool
198 operator==( json_array_iterator_t const &rhs ) const {
199 if( not( *this ) ) {
200 return not rhs;
201 }
202 if( not rhs ) {
203 return false;
204 }
205 return ( m_state.first == rhs.m_state.first );
206 }
207
211 [[nodiscard]] constexpr bool
212 operator!=( json_array_iterator_t const &rhs ) const {
213 if( not( *this ) ) {
214 return static_cast<bool>( rhs );
215 }
216 if( not rhs ) {
217 return true;
218 }
219 return m_state.first != rhs.m_state.first;
220 }
221 };
222
223 template<typename JsonElement, auto... PolicyFlags>
225 JsonElement,
227 options::details::make_parse_flags<PolicyFlags...>( ).value>>>;
233 template<typename JsonElement, auto... PolicyFlags>
236 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
237 using CharT = typename ParseState::CharT;
238
239 static constexpr ParseState get_range( daw::string_view data,
240 daw::string_view member_path ) {
241 auto [result, is_found] = json_details::find_range<ParseState>(
242 DAW_FWD( data ),
243 { std::data( member_path ), std::size( member_path ) } );
244 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
245 daw_json_ensure( result.front( ) == '[', ErrorReason::InvalidArrayStart,
246 result );
247 return result;
248 }
249
250 public:
251 using element_type = json_details::json_deduced_type<JsonElement>;
252 static_assert( not std::is_same_v<element_type, void>,
253 "Unknown JsonElement type." );
254 using value_type = json_details::json_result_t<element_type>;
256 using pointer = json_details::arrow_proxy<value_type>;
257 using difference_type = std::ptrdiff_t;
258
259 private:
260 mutable ParseState m_state = ParseState( );
261
262 public:
263 explicit json_array_iterator_once( ) = default;
264
265 explicit constexpr json_array_iterator_once( daw::string_view jd )
266 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) ) {
267
268 m_state.trim_left( );
269 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
270 ErrorReason::InvalidArrayStart, m_state );
271
272 m_state.remove_prefix( );
273 m_state.trim_left( );
274 }
275
276 explicit constexpr json_array_iterator_once( daw::string_view jd,
277 daw::string_view start_path )
278 : m_state( get_range( jd, start_path ) ) {
279
280 m_state.trim_left( );
281 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
282 ErrorReason::InvalidArrayStart, m_state );
283
284 m_state.remove_prefix( );
285 m_state.trim_left( );
286 }
287
291 [[nodiscard]] constexpr value_type operator*( ) const {
292 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
293 ErrorReason::UnexpectedEndOfData, m_state );
294
295 return json_details::parse_value<element_type, false,
296 element_type::expected_type>(
297 m_state );
298 }
299
300 /***
301 * Move the parse state to the next element
302 * @return iterator after moving
303 */
305 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
306 ErrorReason::UnexpectedEndOfData, m_state );
307 m_state.move_next_member_or_end( );
308 return *this;
309 }
310
314 constexpr void operator++( int ) & {
315 (void)operator++( );
316 }
317
318 /***
319 * Is it ok to dereference iterator
320 * @return true when there is parse data available
321 */
322 [[nodiscard]] constexpr bool good( ) const {
323 return not m_state.is_null( ) and m_state.has_more( ) and
324 m_state.front( ) != ']';
325 }
326
329 [[nodiscard]] explicit constexpr operator bool( ) const {
330 return good( );
331 }
332
336 [[nodiscard]] constexpr bool
338 if( not( *this ) ) {
339 return static_cast<bool>( rhs );
340 }
341 if( not rhs ) {
342 return false;
343 }
344 return ( m_state.first == rhs.m_state.first );
345 }
346
350 [[nodiscard]] constexpr bool
352 if( not( *this ) ) {
353 return not rhs;
354 }
355 if( not rhs ) {
356 return true;
357 }
358 return m_state.first != rhs.m_state.first;
359 }
360 };
361
365 template<typename JsonElement, auto... PolicyFlags>
368 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
369 using iterator = json_array_iterator<JsonElement, PolicyFlags...>;
370 using CharT = typename ParsePolicy::CharT;
371
372 private:
373 iterator m_first{ };
374 iterator m_last{ };
375
376 public:
377 explicit json_array_range( ) = default;
378
379 explicit constexpr json_array_range( daw::string_view jd )
380 : m_first( jd ) {}
381
382 explicit constexpr json_array_range( daw::string_view jd,
383 daw::string_view start_path )
384 : m_first( jd, start_path ) {}
385
387 [[nodiscard]] constexpr iterator begin( ) const {
388 return m_first;
389 }
390
392 [[nodiscard]] constexpr iterator end( ) const {
393 return m_last;
394 }
395
398 [[nodiscard]] constexpr bool empty( ) const {
399 return m_first == m_last;
400 }
401 };
402
407 template<typename JsonElement, auto... PolicyFlags>
410 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
411 using iterator = json_array_iterator_once<JsonElement, PolicyFlags...>;
412 using CharT = typename ParsePolicy::CharT;
413
414 private:
415 iterator m_first{ };
416 iterator m_last{ };
417
418 public:
420
421 explicit constexpr json_array_range_once( daw::string_view jd )
422 : m_first( jd ) {}
423
424 explicit constexpr json_array_range_once( daw::string_view jd,
425 daw::string_view start_path )
426 : m_first( jd, start_path ) {}
427
429 [[nodiscard]] constexpr iterator begin( ) const {
430 return m_first;
431 }
432
434 [[nodiscard]] constexpr iterator end( ) const {
435 return m_last;
436 }
437
440 [[nodiscard]] constexpr bool empty( ) const {
441 return m_first == m_last;
442 }
443 };
444 } // namespace DAW_JSON_VER
445} // namespace daw::json
Iterator for iterating over JSON array's. Requires that op op++ be called in that sequence one time u...
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
Customization point traits.
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