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
31namespace 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:
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::use_direct_construction_v<ParsePolicy,
169 JsonElement> ) {
170 auto const run_after_parse =
171 op_star_cleanup<CharT, ParseState>{ m_can_skip, tmp };
172 (void)run_after_parse;
173 return json_details::parse_value<element_type>(
175 } else {
176 auto result = json_details::parse_value<element_type>(
178
179 m_can_skip = tmp.first;
180 return result;
181 }
182 }
183
184 /***
185 * A dereferencable value proxy holding the result of operator*
186 * This is for compatibility with the Iterator concepts and should be
187 * avoided
188 * @pre good( ) returns true
189 * @return an arrow_proxy of the operator* result
190 */
191 [[nodiscard]] inline pointer operator->( ) const {
192 return pointer{ operator*( ) };
193 }
194
195 /***
196 * Move the parse state to the next element
197 * @return iterator after moving
198 */
199 inline constexpr json_array_iterator &operator++( ) {
200 daw_json_assert_weak( m_state.has_more( ) and m_state.front( ) != ']',
201 ErrorReason::UnexpectedEndOfData, m_state );
202 if( m_can_skip ) {
203 m_state.first = m_can_skip;
204 m_can_skip = nullptr;
205 } else {
206 (void)json_details::skip_known_value<element_type>( m_state );
207 }
208 m_state.move_next_member_or_end( );
209 return *this;
210 }
211
212 /***
213 * Move the parse state to the next element
214 * @return iterator prior to moving
215 */
216 inline constexpr json_array_iterator operator++( int ) & {
217 auto tmp = *this;
218 (void)operator++( );
219 return tmp;
220 }
221
222 /***
223 * Is it ok to dereference iterator
224 * @return true when there is parse data available
225 */
226 [[nodiscard]] inline constexpr bool good( ) const {
227 return not m_state.is_null( ) and m_state.has_more( ) and
228 m_state.front( ) != ']';
229 }
230
231 /***
232 * Are we good( )
233 * @return result of good( )
234 */
235 [[nodiscard]] explicit inline constexpr operator bool( ) const {
236 return good( );
237 }
238
239 /***
240 * Compare rhs for equivalence
241 * @param rhs Another json_array_iterator
242 * @return true when equivalent to rhs
243 */
244 [[nodiscard]] inline constexpr bool
245 operator==( json_array_iterator const &rhs ) const {
246 if( not( *this ) ) {
247 return not rhs;
248 }
249 if( not rhs ) {
250 return false;
251 }
252 return ( m_state.first == rhs.m_state.first );
253 }
254
255 /***
256 * Check if the other iterator is not equivalent
257 * @param rhs another json_array_iterator
258 * @return true when rhs is not equivalent
259 */
260 [[nodiscard]] inline constexpr bool
261 operator!=( json_array_iterator const &rhs ) const {
262 if( not( *this ) ) {
263 return static_cast<bool>( rhs );
264 }
265 if( not rhs ) {
266 return true;
267 }
268 return m_state.first != rhs.m_state.first;
269 }
270 };
271
272 /***
273 * A range of json_array_iterators
274 * @tparam JsonElement Type of each element in array
275 * @tparam ParsePolicy parsing policy type
276 */
277 template<typename JsonElement,
278 typename ParsePolicy = NoCommentSkippingPolicyChecked>
281 using CharT = typename ParsePolicy::CharT;
282
283 private:
284 iterator m_first{ };
285 iterator m_last{ };
286
287 public:
288 constexpr json_array_range( ) = default;
289
290 template<
291 typename String,
292 std::enable_if_t<traits::not_same<json_array_range,
293 daw::remove_cvref_t<String>>::value,
294 std::nullptr_t> = nullptr>
295 constexpr explicit json_array_range( String &&jd )
296 : m_first( DAW_FWD2( String, jd ) ) {
297 static_assert(
298 std::is_convertible_v<decltype( std::data( jd ) ), CharT *> );
299 }
300
301 template<
302 typename String,
303 std::enable_if_t<traits::not_same<json_array_range,
304 daw::remove_cvref_t<String>>::value,
305 std::nullptr_t> = nullptr>
306 constexpr explicit json_array_range( String &&jd,
307 std::string_view start_path )
308 : m_first( DAW_FWD2( String, jd ), start_path ) {
309 static_assert(
310 std::is_convertible_v<decltype( std::data( jd ) ), CharT *>,
311 "Attempt to assign a const char * to a char *" );
312 }
313
314 /***
315 * @return first item in range
316 */
317 [[nodiscard]] inline constexpr iterator begin( ) {
318 return m_first;
319 }
320
321 /***
322 * @return one past last item in range
323 */
324 [[nodiscard]] inline constexpr iterator end( ) {
325 return m_last;
326 }
327
328 /***
329 * Are there any elements in range
330 * @return true when begin( ) == end( )
331 */
332 [[nodiscard]] inline constexpr bool empty( ) const {
333 return m_first == m_last;
334 }
335 };
336 } // namespace DAW_JSON_VER
337} // 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:216
constexpr value_type operator*() const
Definition: daw_json_iterator.h:162
constexpr json_array_iterator(String &&jd)
Definition: daw_json_iterator.h:111
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:226
constexpr bool operator==(json_array_iterator const &rhs) const
Definition: daw_json_iterator.h:245
constexpr bool operator!=(json_array_iterator const &rhs) const
Definition: daw_json_iterator.h:261
constexpr json_array_iterator & operator++()
Definition: daw_json_iterator.h:199
pointer operator->() const
Definition: daw_json_iterator.h:191
std::input_iterator_tag iterator_category
Definition: daw_json_iterator.h:92
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
CharT *& m_can_skip
Definition: daw_json_iterator.h:36
ParseState & tmp
Definition: daw_json_iterator.h:37
typename json_type_deducer< T, is_an_ordered_member_v< 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:953
constexpr bool use_direct_construction_v
Definition: daw_json_parse_common.h:959
daw::constant< v > ParseTag
Definition: daw_json_enums.h:119
BasicParsePolicy<> NoCommentSkippingPolicyChecked
Definition: daw_json_parse_policy.h:550
Definition: daw_from_json.h:22
Definition: daw_from_json.h:22
Definition: daw_json_parse_policy.h:48
Definition: daw_json_iterator.h:279
constexpr bool empty() const
Definition: daw_json_iterator.h:332
typename ParsePolicy::CharT CharT
Definition: daw_json_iterator.h:281
constexpr json_array_range(String &&jd)
Definition: daw_json_iterator.h:295
constexpr iterator end()
Definition: daw_json_iterator.h:324
constexpr json_array_range(String &&jd, std::string_view start_path)
Definition: daw_json_iterator.h:306
json_array_iterator< JsonElement, ParsePolicy > iterator
Definition: daw_json_iterator.h:280
constexpr iterator begin()
Definition: daw_json_iterator.h:317
Definition: daw_json_arrow_proxy.h:16
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16