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 
15 
16 #include <daw/daw_cxmath.h>
17 #include <daw/daw_move.h>
18 #include <daw/daw_scope_guard.h>
19 #include <daw/daw_traits.h>
20 #include <daw/daw_utility.h>
21 
22 #include <array>
23 #include <cstddef>
24 #include <cstdlib>
25 #include <iterator>
26 #include <limits>
27 #include <string>
28 #include <string_view>
29 #include <type_traits>
30 
31 namespace daw::json {
32  inline namespace DAW_JSON_VER {
33  inline namespace {
34  template<typename CharT, typename ParseState>
35  struct op_star_cleanup {
36  CharT *&m_can_skip;
37  ParseState &tmp;
38 
39  DAW_ATTRIB_INLINE
40  DAW_SG_CXDTOR inline ~op_star_cleanup( ) noexcept( false ) {
41 #if defined( DAW_HAS_CONSTEXPR_SCOPE_GUARD )
42  if( DAW_IS_CONSTANT_EVALUATED( ) ) {
43  m_can_skip = tmp.first;
44  } else {
45 #endif
46  if( std::uncaught_exceptions( ) == 0 ) {
47  m_can_skip = tmp.first;
48  }
49 #if defined( DAW_HAS_CONSTEXPR_SCOPE_GUARD )
50  }
51 #endif
52  }
53  };
54  } // namespace
55  /***
56  * Iterator for iterating over JSON array's
57  * @tparam JsonElement type under underlying element in array. If
58  * heterogeneous, a basic_json_value_iterator may be more appropriate
59  * @tparam ParsePolicy Parsing policy type
60  */
61  template<typename JsonElement,
62  typename ParsePolicy = NoCommentSkippingPolicyChecked>
64  using CharT = typename ParsePolicy::CharT;
65 
66  template<typename String>
67  static inline constexpr ParsePolicy
68  get_range( String &&data, std::string_view member_path ) {
69  static_assert(
70  std::is_convertible_v<decltype( std::data( data ) ), CharT *>,
71  "Attempt to assign a const char * to a char *" );
72 
73  auto [is_found, result] = json_details::find_range<ParsePolicy>(
74  DAW_FWD2( String, data ),
75  { std::data( member_path ), std::size( member_path ) } );
76  daw_json_assert( is_found, ErrorReason::JSONPathNotFound );
77  daw_json_assert( result.front( ) == '[', ErrorReason::InvalidArrayStart,
78  result );
79  return result;
80  }
81 
82  public:
83  using element_type =
85  static_assert( traits::not_same<element_type, void>::value,
86  "Unknown JsonElement type." );
87  using value_type = typename element_type::parse_to_t;
90  using difference_type = std::ptrdiff_t;
91  // Can do forward iteration and be stored
92  using iterator_category = std::input_iterator_tag;
93 
94  private:
95  using ParseState = ParsePolicy;
96  ParseState m_state = ParseState( );
97  /***
98  * This lets us fastpath and just skip n characters as we have already
99  * parsed them
100  */
101  mutable CharT *m_can_skip = nullptr;
102 
103  public:
104  inline constexpr json_array_iterator( ) = default;
105 
106  template<
107  typename String,
108  std::enable_if_t<traits::not_same<json_array_iterator,
109  daw::remove_cvref_t<String>>::value,
110  std::nullptr_t> = nullptr>
111  inline constexpr explicit json_array_iterator( String &&jd )
112  : m_state( ParsePolicy( std::data( jd ), daw::data_end( jd ) ) ) {
113 
114  static_assert(
115  traits::is_string_view_like_v<daw::remove_cvref_t<String>>,
116  "String requires being able to call std::data/std::size. char const "
117  "* are not able to do this, pass a string_view for char const * to "
118  "ensure you are aware of the strlen cost" );
119 
120  static_assert(
121  std::is_convertible_v<decltype( std::data( jd ) ), CharT *> );
122  m_state.trim_left( );
123  daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
124  ErrorReason::InvalidArrayStart, m_state );
125 
126  m_state.remove_prefix( );
127  m_state.trim_left( );
128  }
129 
130  template<
131  typename String,
132  std::enable_if_t<traits::not_same<json_array_iterator,
133  daw::remove_cvref_t<String>>::value,
134  std::nullptr_t> = nullptr>
135  inline constexpr explicit json_array_iterator(
136  String &&jd, std::string_view start_path )
137  : m_state( get_range( DAW_FWD2( String, jd ), start_path ) ) {
138 
139  static_assert(
140  traits::is_string_view_like_v<daw::remove_cvref_t<String>>,
141  "String requires being able to call std::data/std::size. char const "
142  "* are not able to do this, pass a string_view for char const * to "
143  "ensure you are aware of the strlen cost" );
144 
145  static_assert(
146  std::is_convertible_v<decltype( std::data( jd ) ), CharT *>,
147  "Attempt to assign a const char * to a char *" );
148 
149  m_state.trim_left( );
150  daw_json_assert_weak( m_state.is_opening_bracket_checked( ),
151  ErrorReason::InvalidArrayStart, m_state );
152 
153  m_state.remove_prefix( );
154  m_state.trim_left( );
155  }
156 
157  /***
158  * Parse the current element
159  * @pre good( ) returns true
160  * @return The parsed result of ParseElement
161  */
162  [[nodiscard]] inline constexpr value_type operator*( ) const {
163  daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
164  ErrorReason::UnexpectedEndOfData, m_state );
165 
166  auto tmp = m_state;
167 
168  if constexpr( json_details::is_guaranteed_rvo_v<ParsePolicy> ) {
169  auto const run_after_parse =
170  op_star_cleanup<CharT, ParseState>{ m_can_skip, tmp };
171  (void)run_after_parse;
172  return json_details::parse_value<element_type>(
174  } else {
175  auto result = json_details::parse_value<element_type>(
177 
178  m_can_skip = tmp.first;
179  return result;
180  }
181  }
182 
183  /***
184  * A dereferencable value proxy holding the result of operator*
185  * This is for compatibility with the Iterator concepts and should be
186  * avoided
187  * @pre good( ) returns true
188  * @return an arrow_proxy of the operator* result
189  */
190  [[nodiscard]] inline pointer operator->( ) const {
191  return pointer{ operator*( ) };
192  }
193 
194  /***
195  * Move the parse state to the next element
196  * @return iterator after moving
197  */
198  inline constexpr json_array_iterator &operator++( ) {
199  daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
200  ErrorReason::UnexpectedEndOfData, m_state );
201  if( m_can_skip ) {
202  m_state.first = m_can_skip;
203  m_can_skip = nullptr;
204  } else {
205  (void)json_details::skip_known_value<element_type>( m_state );
206  }
207  m_state.move_next_member_or_end( );
208  return *this;
209  }
210 
211  /***
212  * Move the parse state to the next element
213  * @return iterator prior to moving
214  */
215  inline constexpr json_array_iterator operator++( int ) & {
216  auto tmp = *this;
217  (void)operator++( );
218  return tmp;
219  }
220 
221  /***
222  * Is it ok to dereference iterator
223  * @return true when there is parse data available
224  */
225  [[nodiscard]] inline constexpr bool good( ) const {
226  return not m_state.is_null( ) and m_state.has_more( ) and
227  m_state.front( ) != ']';
228  }
229 
230  /***
231  * Are we good( )
232  * @return result of good( )
233  */
234  [[nodiscard]] explicit inline constexpr operator bool( ) const {
235  return good( );
236  }
237 
238  /***
239  * Compare rhs for equivalence
240  * @param rhs Another json_array_iterator
241  * @return true when equivalent to rhs
242  */
243  [[nodiscard]] inline constexpr bool
244  operator==( json_array_iterator const &rhs ) const {
245  if( not( *this ) ) {
246  return not rhs;
247  }
248  if( not rhs ) {
249  return false;
250  }
251  return ( m_state.first == rhs.m_state.first );
252  }
253 
254  /***
255  * Check if the other iterator is not equivalent
256  * @param rhs another json_array_iterator
257  * @return true when rhs is not equivalent
258  */
259  [[nodiscard]] inline constexpr bool
260  operator!=( json_array_iterator const &rhs ) const {
261  if( not( *this ) ) {
262  return static_cast<bool>( rhs );
263  }
264  if( not rhs ) {
265  return true;
266  }
267  return m_state.first != rhs.m_state.first;
268  }
269  };
270 
271  /***
272  * A range of json_array_iterators
273  * @tparam JsonElement Type of each element in array
274  * @tparam ParsePolicy parsing policy type
275  */
276  template<typename JsonElement,
277  typename ParsePolicy = NoCommentSkippingPolicyChecked>
280  using CharT = typename ParsePolicy::CharT;
281 
282  private:
283  iterator m_first{ };
284  iterator m_last{ };
285 
286  public:
287  constexpr json_array_range( ) = default;
288 
289  template<
290  typename String,
291  std::enable_if_t<traits::not_same<json_array_range,
292  daw::remove_cvref_t<String>>::value,
293  std::nullptr_t> = nullptr>
294  constexpr explicit json_array_range( String &&jd )
295  : m_first( DAW_FWD2( String, jd ) ) {
296  static_assert(
297  std::is_convertible_v<decltype( std::data( jd ) ), CharT *> );
298  }
299 
300  template<
301  typename String,
302  std::enable_if_t<traits::not_same<json_array_range,
303  daw::remove_cvref_t<String>>::value,
304  std::nullptr_t> = nullptr>
305  constexpr explicit json_array_range( String &&jd,
306  std::string_view start_path )
307  : m_first( DAW_FWD2( String, jd ), start_path ) {
308  static_assert(
309  std::is_convertible_v<decltype( std::data( jd ) ), CharT *>,
310  "Attempt to assign a const char * to a char *" );
311  }
312 
313  /***
314  * @return first item in range
315  */
316  [[nodiscard]] inline constexpr iterator begin( ) {
317  return m_first;
318  }
319 
320  /***
321  * @return one past last item in range
322  */
323  [[nodiscard]] inline constexpr iterator end( ) {
324  return m_last;
325  }
326 
327  /***
328  * Are there any elements in range
329  * @return true when begin( ) == end( )
330  */
331  [[nodiscard]] inline constexpr bool empty( ) const {
332  return m_first == m_last;
333  }
334  };
335  } // namespace DAW_JSON_VER
336 } // namespace daw::json
Definition: daw_json_iterator.h:63
typename element_type::parse_to_t value_type
Definition: daw_json_iterator.h:87
std::ptrdiff_t difference_type
Definition: daw_json_iterator.h:90
constexpr json_array_iterator(String &&jd, std::string_view start_path)
Definition: daw_json_iterator.h:135
constexpr json_array_iterator operator++(int) &
Definition: daw_json_iterator.h:215
constexpr value_type operator*() const
Definition: daw_json_iterator.h:162
constexpr json_array_iterator(String &&jd)
Definition: daw_json_iterator.h:111
constexpr json_array_iterator & operator++()
Definition: daw_json_iterator.h:198
typename json_details::json_deduced_type< JsonElement >::without_name element_type
Definition: daw_json_iterator.h:84
value_type reference
Definition: daw_json_iterator.h:88
constexpr bool good() const
Definition: daw_json_iterator.h:225
constexpr bool operator==(json_array_iterator const &rhs) const
Definition: daw_json_iterator.h:244
constexpr bool operator!=(json_array_iterator const &rhs) const
Definition: daw_json_iterator.h:260
pointer operator->() const
Definition: daw_json_iterator.h:190
std::input_iterator_tag iterator_category
Definition: daw_json_iterator.h:92
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:189
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:178
CharT *& m_can_skip
Definition: daw_json_iterator.h:36
ParseState & tmp
Definition: daw_json_iterator.h:37
typename json_type_deducer< T, has_json_data_contract_trait_v< T >, json_details::is_a_json_type_v< T >, has_json_link_quick_map_v< T >, is_container_v< T > >::type json_deduced_type
Definition: daw_json_parse_common.h:931
constexpr bool is_string_view_like_v
Definition: daw_json_traits.h:499
std::integral_constant< JsonParseTypes, v > ParseTag
Definition: daw_json_enums.h:106
BasicParsePolicy<> NoCommentSkippingPolicyChecked
Definition: daw_json_parse_policy.h:540
Definition: daw_from_json.h:22
Definition: daw_from_json.h:22
Definition: daw_json_parse_policy.h:47
Definition: daw_json_iterator.h:278
constexpr bool empty() const
Definition: daw_json_iterator.h:331
typename ParsePolicy::CharT CharT
Definition: daw_json_iterator.h:280
constexpr json_array_range(String &&jd)
Definition: daw_json_iterator.h:294
constexpr iterator end()
Definition: daw_json_iterator.h:323
constexpr json_array_range(String &&jd, std::string_view start_path)
Definition: daw_json_iterator.h:305
json_array_iterator< JsonElement, ParsePolicy > iterator
Definition: daw_json_iterator.h:279
constexpr iterator begin()
Definition: daw_json_iterator.h:316
Definition: daw_json_arrow_proxy.h:16
#define DAW_JSON_VER
Definition: version.h:11