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 } // 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
63 static constexpr ParseState get_range( daw::string_view data,
64 daw::string_view member_path ) {
65 auto [result, is_found] = json_details::find_range<ParseState>(
66 DAW_FWD( data ),
67 { std::data( member_path ), std::size( member_path ) } );
68 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
70 result.front( ) == '[', ErrorReason::InvalidArrayStart, result );
71 return result;
72 }
73
74 public:
75 using element_type = json_details::json_deduced_type<JsonElement>;
76 static_assert( not std::is_same_v<element_type, void>,
77 "Unknown JsonElement type." );
78 using value_type = json_details::json_result_t<element_type>;
80 using pointer = json_details::arrow_proxy<value_type>;
81 using difference_type = std::ptrdiff_t;
82 // Can do forward iteration and be stored
83 using iterator_category = std::input_iterator_tag;
84
85 private:
86 ParseState m_state = ParseState( );
87 /***
88 * This lets us fastpath and just skip n characters as we have already
89 * parsed them
90 */
91 mutable char const *m_can_skip = nullptr;
92
93 public:
94 explicit json_array_iterator_t( ) = default;
95
96 explicit constexpr json_array_iterator_t( daw::string_view jd )
97 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) ) {
98
99 m_state.trim_left( );
100 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
101 ErrorReason::InvalidArrayStart,
102 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,
115 m_state );
116
117 m_state.remove_prefix( );
118 m_state.trim_left( );
119 }
120
122 constexpr json_array_iterator_t begin( ) const {
123 return *this;
124 }
125
127 constexpr json_array_iterator_t end( ) const {
128 return json_array_iterator_t( );
129 }
130
134 [[nodiscard]] constexpr value_type operator*( ) const {
135 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
136 ErrorReason::UnexpectedEndOfData,
137 m_state );
138
139 auto tmp = m_state;
140
141 auto const run_after_parse =
142 json_details::assign_on_dtor{ m_can_skip, tmp.first };
143 (void)run_after_parse;
144 return json_details::
145 parse_value<element_type, false, element_type::expected_type>( tmp );
146 }
147
153 [[nodiscard]] pointer operator->( ) const {
154 return pointer{ operator*( ) };
155 }
156
157 /***
158 * Move the parse state to the next element
159 * @return iterator after moving
160 */
162 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
163 ErrorReason::UnexpectedEndOfData,
164 m_state );
165 if( m_can_skip ) {
166 m_state.first = m_can_skip;
167 m_can_skip = nullptr;
168 } else {
169 (void)json_details::skip_known_value<element_type>( m_state );
170 }
171 m_state.move_next_member_or_end( );
172 return *this;
173 }
174
178 constexpr void operator++( int ) & {
179 (void)operator++( );
180 }
181
182 /***
183 * Is it ok to dereference iterator
184 * @return true when there is parse data available
185 */
186 [[nodiscard]] constexpr bool good( ) const {
187 return not m_state.is_null( ) and m_state.has_more( ) and
188 m_state.front( ) != ']';
189 }
190
193 [[nodiscard]] explicit constexpr operator bool( ) const {
194 return good( );
195 }
196
200 [[nodiscard]] constexpr bool
201 operator==( json_array_iterator_t const &rhs ) const {
202 if( not( *this ) ) {
203 return not rhs;
204 }
205 if( not rhs ) {
206 return false;
207 }
208 return ( m_state.first == rhs.m_state.first );
209 }
210
214 [[nodiscard]] constexpr bool
215 operator!=( json_array_iterator_t const &rhs ) const {
216 if( not( *this ) ) {
217 return static_cast<bool>( rhs );
218 }
219 if( not rhs ) {
220 return true;
221 }
222 return m_state.first != rhs.m_state.first;
223 }
224 };
225
226 template<typename JsonElement, auto... PolicyFlags>
228 JsonElement,
230 options::details::make_parse_flags<PolicyFlags...>( ).value>>>;
236 template<typename JsonElement, auto... PolicyFlags>
239 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
240
241 static constexpr ParseState get_range( daw::string_view data,
242 daw::string_view member_path ) {
243 auto [result, is_found] = json_details::find_range<ParseState>(
244 DAW_FWD( data ),
245 { std::data( member_path ), std::size( member_path ) } );
246 daw_json_ensure( is_found, ErrorReason::JSONPathNotFound );
248 result.front( ) == '[', ErrorReason::InvalidArrayStart, result );
249 return result;
250 }
251
252 public:
253 using element_type = json_details::json_deduced_type<JsonElement>;
254 static_assert( not std::is_same_v<element_type, void>,
255 "Unknown JsonElement type." );
256 using value_type = json_details::json_result_t<element_type>;
258 using pointer = json_details::arrow_proxy<value_type>;
259 using difference_type = std::ptrdiff_t;
260
261 private:
262 mutable ParseState m_state = ParseState( );
263
264 public:
265 explicit json_array_iterator_once( ) = default;
266
267 explicit constexpr json_array_iterator_once( daw::string_view jd )
268 : m_state( ParseState( std::data( jd ), daw::data_end( jd ) ) ) {
269
270 m_state.trim_left( );
271 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
272 ErrorReason::InvalidArrayStart,
273 m_state );
274
275 m_state.remove_prefix( );
276 m_state.trim_left( );
277 }
278
279 explicit constexpr json_array_iterator_once( daw::string_view jd,
280 daw::string_view start_path )
281 : m_state( get_range( jd, start_path ) ) {
282
283 m_state.trim_left( );
284 daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
285 ErrorReason::InvalidArrayStart,
286 m_state );
287
288 m_state.remove_prefix( );
289 m_state.trim_left( );
290 }
291
295 [[nodiscard]] constexpr value_type operator*( ) const {
296 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
297 ErrorReason::UnexpectedEndOfData,
298 m_state );
299
300 return json_details::
301 parse_value<element_type, false, element_type::expected_type>(
302 m_state );
303 }
304
305 /***
306 * Move the parse state to the next element
307 * @return iterator after moving
308 */
310 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
311 ErrorReason::UnexpectedEndOfData,
312 m_state );
313 m_state.move_next_member_or_end( );
314 return *this;
315 }
316
320 constexpr void operator++( int ) & {
321 (void)operator++( );
322 }
323
324 /***
325 * Is it ok to dereference iterator
326 * @return true when there is parse data available
327 */
328 [[nodiscard]] constexpr bool good( ) const {
329 return not m_state.is_null( ) and m_state.has_more( ) and
330 m_state.front( ) != ']';
331 }
332
335 [[nodiscard]] explicit constexpr operator bool( ) const {
336 return good( );
337 }
338
342 [[nodiscard]] constexpr bool
344 if( not( *this ) ) {
345 return static_cast<bool>( rhs );
346 }
347 if( not rhs ) {
348 return false;
349 }
350 return ( m_state.first == rhs.m_state.first );
351 }
352
356 [[nodiscard]] constexpr bool
358 if( not( *this ) ) {
359 return not rhs;
360 }
361 if( not rhs ) {
362 return true;
363 }
364 return m_state.first != rhs.m_state.first;
365 }
366 };
367
371 template<typename JsonElement, auto... PolicyFlags>
374 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
375 using iterator = json_array_iterator<JsonElement, PolicyFlags...>;
376
377 private:
378 iterator m_first{ };
379 iterator m_last{ };
380
381 public:
382 explicit json_array_range( ) = default;
383
384 explicit constexpr json_array_range( daw::string_view jd )
385 : m_first( jd ) {}
386
387 explicit constexpr json_array_range( daw::string_view jd,
388 daw::string_view start_path )
389 : m_first( jd, start_path ) {}
390
392 [[nodiscard]] constexpr iterator begin( ) const {
393 return m_first;
394 }
395
397 [[nodiscard]] constexpr iterator end( ) const {
398 return m_last;
399 }
400
403 [[nodiscard]] constexpr bool empty( ) const {
404 return m_first == m_last;
405 }
406 };
407
412 template<typename JsonElement, auto... PolicyFlags>
415 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
416 using iterator = json_array_iterator_once<JsonElement, PolicyFlags...>;
417
418 private:
419 iterator m_first{ };
420 iterator m_last{ };
421
422 public:
424
425 explicit constexpr json_array_range_once( daw::string_view jd )
426 : m_first( jd ) {}
427
428 explicit constexpr json_array_range_once( daw::string_view jd,
429 daw::string_view start_path )
430 : m_first( jd, start_path ) {}
431
433 [[nodiscard]] constexpr iterator begin( ) const {
434 return m_first;
435 }
436
438 [[nodiscard]] constexpr iterator end( ) const {
439 return m_last;
440 }
441
444 [[nodiscard]] constexpr bool empty( ) const {
445 return m_first == m_last;
446 }
447 };
448 } // namespace DAW_JSON_VER
449} // 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