DAW JSON Link
daw_json_parse_kv_class_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"
15 #include "daw_json_parse_name.h"
17 #include "daw_json_traits.h"
18 
19 #include <daw/daw_move.h>
20 
21 #include <cstddef>
22 #include <iterator>
23 
24 namespace daw::json {
25  inline namespace DAW_JSON_VER {
26  namespace json_details {
27  template<typename ParseState, bool>
28  struct json_parse_kv_class_iterator_base {
29  using iterator_category = std::input_iterator_tag;
30  using difference_type = std::ptrdiff_t;
31  ParseState *parse_state = nullptr;
32  };
33 
34  template<typename ParseState>
35  struct json_parse_kv_class_iterator_base<ParseState, true> {
36 #if defined( DAW_JSON_HAS_CPP23_RANGE_CTOR )
37  using iterator_category = std::input_iterator_tag;
38 #else
39  // We have to lie so that std::distance uses O(1) instead of O(N)
40  using iterator_category = std::random_access_iterator_tag;
41 #endif
42  using difference_type = std::ptrdiff_t;
43  ParseState *parse_state = nullptr;
44 
45  constexpr difference_type
46  operator-( json_parse_kv_class_iterator_base const &rhs ) const {
47  if( rhs.parse_state ) {
48  return static_cast<difference_type>( rhs.parse_state->counter );
49  }
50  return 0;
51  }
52  };
53 
54  namespace kv_class_iter_impl {
55  template<typename T>
56  using container_value_t = typename T::value_type;
57 
58  template<typename JsonMember>
59  using default_value_type =
60  std::pair<typename JsonMember::json_key_t,
61  typename JsonMember::json_element_t>;
62 
63  template<typename JsonMember, typename T>
64  using container_value_type_or =
65  daw::detected_or_t<default_value_type<JsonMember>, container_value_t,
66  T>;
67  } // namespace kv_class_iter_impl
68 
69  template<typename JsonMember, typename ParseState, bool IsKnown>
70  struct json_parse_kv_class_iterator
71  : json_parse_kv_class_iterator_base<ParseState,
72  can_be_random_iterator_v<IsKnown>> {
73 
74  using base =
75  json_parse_kv_class_iterator_base<ParseState,
76  can_be_random_iterator_v<IsKnown>>;
77  using iterator_category = typename base::iterator_category;
78  using element_t = typename JsonMember::json_element_t;
79  using member_container_type = json_base_type_t<JsonMember>;
80  using value_type =
81  kv_class_iter_impl::container_value_type_or<JsonMember,
82  member_container_type>;
83  using reference = value_type;
84  using pointer = arrow_proxy<value_type>;
85  using iterator_range_t = ParseState;
86  using difference_type = typename base::difference_type;
87 
88  using key_t = typename JsonMember::json_key_t;
89  using value_t = typename JsonMember::json_element_t;
90 
91  json_parse_kv_class_iterator( ) = default;
92 
93  constexpr explicit json_parse_kv_class_iterator( iterator_range_t &r )
94  : base{ &r } {
95  daw_json_ensure( not IsKnown and not base::parse_state->empty( ),
96  ErrorReason::UnexpectedEndOfData );
97  if( base::parse_state->front( ) == '}' ) {
98  // Cleanup at end of value
99  if( not IsKnown ) {
100  base::parse_state->remove_prefix( );
101  base::parse_state->trim_left_checked( );
102  // Ensure we are equal to default
103  }
104  base::parse_state = nullptr;
105  }
106  }
107 
108  [[noreturn]] DAW_ATTRIB_NOINLINE value_type operator*( ) const {
109  // This is hear to satisfy indirectly_readable
110  daw_json_error( ErrorReason::UnexpectedEndOfData );
111  }
112 
113  constexpr value_type operator*( ) {
115  base::parse_state and base::parse_state->has_more( ),
116  ErrorReason::UnexpectedEndOfData, *base::parse_state );
117  auto key = parse_value<key_t, false, key_t::expected_type>(
118  *base::parse_state );
119  name::name_parser::trim_end_of_name( *base::parse_state );
120 
121  return json_class_constructor<value_type,
123  std::move( key ),
124  parse_value<value_t, false, value_t::expected_type>(
125  *base::parse_state ) );
126  }
127 
128  constexpr json_parse_kv_class_iterator &operator++( ) {
129  daw_json_assert_weak( base::parse_state,
130  ErrorReason::AttemptToAccessPastEndOfValue,
131  *base::parse_state );
132  base::parse_state->move_next_member_or_end( );
133  daw_json_assert_weak( base::parse_state->has_more( ),
134  ErrorReason::UnexpectedEndOfData,
135  *base::parse_state );
136  if( base::parse_state->front( ) == '}' ) {
137 #if not defined( NDEBUG )
138  if constexpr( IsKnown ) {
139  if( base::parse_state ) {
140  daw_json_ensure( base::parse_state->counter == 0,
141  ErrorReason::AttemptToAccessPastEndOfValue,
142  *base::parse_state );
143  base::parse_state->counter--;
144  }
145  }
146 #endif
147  // Cleanup at end of value
148  base::parse_state->remove_prefix( );
149  base::parse_state->trim_left_checked( );
150  // Ensure we are equal to default
151  base::parse_state = nullptr;
152  }
153 #if not defined( NDEBUG )
154  if constexpr( IsKnown ) {
155  if( base::parse_state ) {
156  daw_json_ensure( base::parse_state->counter > 0,
157  ErrorReason::AttemptToAccessPastEndOfValue,
158  *base::parse_state );
159  base::parse_state->counter--;
160  }
161  }
162 #endif
163  return *this;
164  }
165 
166  DAW_ATTRIB_INLINE constexpr void operator++( int ) {
167  (void)operator++( );
168  }
169 
170  friend constexpr bool
171  operator==( json_parse_kv_class_iterator const &lhs,
172  json_parse_kv_class_iterator const &rhs ) {
173  // using identity as equality
174  return lhs.parse_state == rhs.base::parse_state;
175  }
176 
177  friend constexpr bool
178  operator!=( json_parse_kv_class_iterator const &lhs,
179  json_parse_kv_class_iterator const &rhs ) {
180  return not( lhs == rhs );
181  }
182  };
183  } // namespace json_details
184  } // namespace DAW_JSON_VER
185 } // 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_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
Customization point traits.
Default Constructor for a type. It accounts for aggregate types and uses brace construction for them.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25