DAW JSON Link
daw_json_parse_array_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 "version.h"
12 
13 #include "daw_json_arrow_proxy.h"
14 #include "daw_json_assert.h"
16 
17 #include <daw/daw_attributes.h>
18 
19 #include <type_traits>
20 
21 namespace daw::json {
22  inline namespace DAW_JSON_VER {
23  namespace json_details {
24  template<typename ParseState, bool>
25  struct json_parse_array_iterator_base {
26  using iterator_category = std::input_iterator_tag;
27  using difference_type = std::ptrdiff_t;
28  static constexpr bool has_counter = false;
29 
30  ParseState *parse_state = nullptr;
31  };
32 
33  template<typename ParseState>
34  struct json_parse_array_iterator_base<ParseState, true> {
35 #if defined( DAW_JSON_HAS_CPP23_RANGE_CTOR )
36  using iterator_category = std::input_iterator_tag;
37 #else
38  using iterator_category = std::random_access_iterator_tag;
39 #endif
40  using difference_type = std::ptrdiff_t;
41  static constexpr bool has_counter = true;
42 
43  ParseState *parse_state = nullptr;
44  difference_type counter = 0;
45 
46  explicit json_parse_array_iterator_base( ) = default;
47 
48  DAW_ATTRIB_NONNULL( )
49  explicit inline constexpr
50  json_parse_array_iterator_base( ParseState *pd ) noexcept
51  : parse_state( pd )
52  , counter( static_cast<difference_type>( pd->counter ) ) {}
53 
54  constexpr difference_type
55  operator-( json_parse_array_iterator_base const &rhs ) const {
56  // rhs is the iterator with the parser in it. We should know how many
57  // items are in play because we already counted them in the skip_array
58  // call.
59 
60  return rhs.counter;
61  }
62  };
63 
64  template<typename JsonMember, typename ParseState, bool KnownBounds>
65  struct json_parse_array_iterator
66  : json_parse_array_iterator_base<
67  ParseState, can_be_random_iterator_v<KnownBounds>> {
68 
69  using base =
70  json_parse_array_iterator_base<ParseState,
71  can_be_random_iterator_v<KnownBounds>>;
72 
73  using iterator_category = typename base::iterator_category;
74  using element_t = typename JsonMember::json_element_t;
75  using value_type = json_result_t<element_t>;
76  using reference = value_type;
77  using pointer = arrow_proxy<value_type>;
78  using parse_state_t = ParseState;
79  using difference_type = typename base::difference_type;
80  using size_type = std::size_t;
81 
82  json_parse_array_iterator( ) = default;
83 #if defined( DAW_JSON_USE_FULL_DEBUG_ITERATORS )
84  // This code requires C++ 20 to be useful in a constant expression as it
85  // requires a non-trivial destructor
86  json_parse_array_iterator( json_parse_array_iterator const & ) =
87  default;
88  json_parse_array_iterator &
89  operator=( json_parse_array_iterator const & ) = default;
90  json_parse_array_iterator( json_parse_array_iterator && ) = default;
91  json_parse_array_iterator &
92  operator=( json_parse_array_iterator && ) = default;
93  DAW_JSON_CPP20_CX_DTOR ~json_parse_array_iterator( ) {
94  if constexpr( base::has_counter ) {
95  daw_json_assert_weak( base::counter == 0,
96  ErrorReason::AttemptToAccessPastEndOfValue );
97  }
98  }
99 #endif
100  constexpr explicit json_parse_array_iterator( parse_state_t &r )
101  : base{ &r } {
102  if( DAW_UNLIKELY( base::parse_state->front( ) == ']' ) ) {
103  if constexpr( not KnownBounds ) {
104  // Cleanup at end of value
105  base::parse_state->remove_prefix( );
106  base::parse_state->trim_left_checked( );
107  // Ensure we are equal to default
108  }
109  base::parse_state = nullptr;
110  }
111  }
112 
113  [[noreturn]] DAW_ATTRIB_NOINLINE value_type operator*( ) const {
114  DAW_UNLIKELY_BRANCH
115  // This is hear to satisfy indirectly_readable
116  daw_json_error( ErrorReason::UnexpectedEndOfData );
117  }
118 
119  DAW_ATTRIB_INLINE constexpr value_type operator*( ) {
121  base::parse_state and base::parse_state->has_more( ),
122  ErrorReason::UnexpectedEndOfData, *base::parse_state );
123 
124  return parse_value<element_t, false, element_t::expected_type>(
125  *base::parse_state );
126  }
127 
128  DAW_ATTRIB_INLINE constexpr json_parse_array_iterator &operator++( ) {
129  daw_json_assert_weak( base::parse_state,
130  ErrorReason::UnexpectedEndOfData,
131  *base::parse_state );
132  base::parse_state->trim_left( );
133 
135  base::parse_state->has_more( ) and
136  base::parse_state->is_at_next_array_element( ),
137  ErrorReason::UnexpectedEndOfData, *base::parse_state );
138 
139  base::parse_state->move_next_member_or_end( );
140  daw_json_assert_weak( base::parse_state->has_more( ),
141  ErrorReason::UnexpectedEndOfData,
142  *base::parse_state );
143  if( base::parse_state->front( ) == ']' ) {
144 #if not defined( NDEBUG )
145  if constexpr( base::has_counter ) {
146  daw_json_assert_weak( base::counter == 0,
147  ErrorReason::AttemptToAccessPastEndOfValue,
148  *base::parse_state );
149  }
150 #endif
151  if constexpr( not KnownBounds ) {
152  // Cleanup at end of value
153  base::parse_state->remove_prefix( );
154  base::parse_state->trim_left_checked( );
155  // Ensure we are equal to default
156  }
157  base::parse_state = nullptr;
158  } else {
159 #if not defined( NDEBUG )
160  if constexpr( base::has_counter ) {
161  daw_json_assert_weak( base::counter > 0,
162  ErrorReason::AttemptToAccessPastEndOfValue,
163  *base::parse_state );
164  --base::counter;
165  }
166 #endif
167  }
168  return *this;
169  }
170 
171  DAW_ATTRIB_INLINE constexpr void operator++( int ) {
172  (void)operator++( );
173  }
174 
175  friend inline constexpr bool
176  operator==( json_parse_array_iterator const &lhs,
177  json_parse_array_iterator const &rhs ) {
178  return lhs.parse_state == rhs.parse_state;
179  }
180 
181  friend inline constexpr bool
182  operator!=( json_parse_array_iterator const &lhs,
183  json_parse_array_iterator const &rhs ) {
184  return not( lhs == rhs );
185  }
186 
187  constexpr json_parse_array_iterator &begin( ) {
188  return *this;
189  }
190 
191  constexpr json_parse_array_iterator end( ) const {
192  return { };
193  }
194  };
195  } // namespace json_details
196  } // namespace DAW_JSON_VER
197 } // namespace daw::json
#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_CPP20_CX_DTOR
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25