DAW JSON Link
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 
32 namespace 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  */
159  constexpr json_array_iterator_t &operator++( ) {
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  */
304  constexpr json_array_iterator_once &operator++( ) {
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
337  operator==( json_array_iterator_once const &rhs ) const {
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
351  operator!=( json_array_iterator_once const &rhs ) const {
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:
419  json_array_range_once( ) = default;
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.
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParseState
constexpr bool operator==(json_array_iterator_once const &rhs) const
Compare rhs for equivalence.
constexpr bool operator==(json_array_iterator_t const &rhs) const
Compare rhs for equivalence.
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...
#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...
TryDefaultParsePolicy< BasicParsePolicy< options::details::make_parse_flags< PolicyFlags... >().value > > ParsePolicy
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:25