DAW JSON Link
daw_json_value_state.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 
14 #include "impl/daw_json_value.h"
15 #include "impl/daw_murmur3.h"
16 
17 #include <daw/daw_uint_buffer.h>
18 
19 #include <ciso646>
20 #include <cstddef>
21 #include <string_view>
22 #include <utility>
23 #include <vector>
24 
25 namespace daw::json {
26  namespace json_details {
27  template<typename Range>
28  struct basic_stateful_json_value_state {
29  daw::string_view name;
30  daw::UInt32 hash_value;
31  basic_json_value_iterator<Range> location;
32 
33  explicit constexpr basic_stateful_json_value_state(
34  daw::string_view Name, basic_json_value_iterator<Range> val )
35  : name( Name )
36  , hash_value( daw::name_hash( Name ) )
37  , location( std::move( val ) ) {}
38 
39  [[nodiscard]] constexpr bool is_match( daw::string_view Name ) const {
40  return name == Name;
41  }
42 
43  [[nodiscard]] constexpr bool is_match( daw::string_view Name,
44  daw::UInt32 hash ) const {
45  if( hash != hash_value ) {
46  return false;
47  }
48  return name == Name;
49  }
50  };
51  } // namespace json_details
52 
54  daw::string_view name;
55  daw::UInt32 hash_value;
56 
57  constexpr json_member_name( std::string_view Name )
58  : name( Name.data( ), Name.size( ) )
59  , hash_value( daw::name_hash( name ) ) {}
60  };
61 
67  template<typename Range>
70  std::vector<json_details::basic_stateful_json_value_state<Range>> m_locs{ };
71 
72  /***
73  * Move parser until member name matches key if needed
74  * @param member to move_to
75  * @return position of member or size
76  */
77  [[nodiscard]] constexpr std::size_t move_to( json_member_name member ) {
78  std::size_t pos = 0;
79  for( ; pos < m_locs.size( ); ++pos ) {
80  if( m_locs[pos].is_match( member.name, member.hash_value ) ) {
81  return pos;
82  }
83  }
84 
85  auto it = [&] {
86  if( m_locs.empty( ) ) {
87  return m_value.begin( );
88  }
89  auto res = m_locs.back( ).location;
90  ++res;
91  return res;
92  }( );
93  auto const last = m_value.end( );
94  while( it != last ) {
95  auto name = it.name( );
96  daw_json_assert_weak( name, ErrorReason::MissingMemberName );
97  auto const &new_loc = m_locs.emplace_back(
98  daw::string_view( name->data( ), name->size( ) ), it );
99  if( new_loc.is_match( member.name ) ) {
100  return pos;
101  }
102  ++pos;
103  ++it;
104  }
105  return m_locs.size( );
106  }
107 
108  /***
109  * Move parser until member index matches, if needed
110  * @param index position of member to move to
111  * @return position in members or size
112  */
113  [[nodiscard]] constexpr std::size_t move_to( std::size_t index ) {
114  if( index < m_locs.size( ) ) {
115  return index;
116  }
117  auto it = [&] {
118  if( m_locs.empty( ) ) {
119  return m_value.begin( );
120  }
121  auto res = m_locs.back( ).location;
122  ++res;
123  return res;
124  }( );
125  auto last = m_value.end( );
126  std::size_t pos = m_locs.size( );
127  while( it != last ) {
128  auto name = it.name( );
129  if( name ) {
130  m_locs.emplace_back( daw::string_view( name->data( ), name->size( ) ),
131  it );
132  } else {
133  m_locs.emplace_back( daw::string_view( ), it );
134  }
135  if( pos == index ) {
136  return pos;
137  }
138  ++pos;
139  ++it;
140  }
141  return m_locs.size( );
142  }
143 
144  public:
146  : m_value( std::move( val ) ) {
147 
148  daw_json_assert_weak( ( [&] {
149  auto t = m_value.type( );
150  return ( t == JsonBaseParseTypes::Class ) |
151  ( t == JsonBaseParseTypes::Array );
152  }( ) ),
153  ErrorReason::ExpectedArrayOrClassStart,
154  val.get_range( ) );
155  }
156 
158  : basic_stateful_json_value( basic_json_value<Range>( "{}" ) ) {}
159 
160  constexpr basic_stateful_json_value( std::string_view json_data )
161  : basic_stateful_json_value( basic_json_value<Range>( json_data ) ) {}
166  constexpr void reset( basic_json_value<Range> val ) {
167  m_value = std::move( val );
168  m_locs.clear( );
169  }
170 
171  /***
172  * Create a basic_json_member for the named member
173  * @pre name must be valid
174  * @param key name of member
175  * @return a new basic_json_member
176  */
177  [[nodiscard]] constexpr basic_json_value<Range>
178  operator[]( std::string_view key ) {
179  std::size_t pos = move_to( json_member_name( key ) );
180  daw_json_assert_weak( pos < m_locs.size( ), ErrorReason::UnknownMember );
181  return m_locs[pos].location->value;
182  }
183 
184  /***
185  * Create a basic_json_member for the named member
186  * @pre name must be valid
187  * @param member name of member
188  * @return a new basic_json_member
189  */
190  [[nodiscard]] constexpr basic_json_value<Range>
192  std::size_t pos = move_to( member );
193  daw_json_assert_weak( pos < m_locs.size( ), ErrorReason::UnknownMember );
194  return m_locs[pos].location->value;
195  }
196 
197  /***
198  * Create a basic_json_member for the named member
199  * @pre name must be valid
200  * @param key name of member
201  * @return a new basic_json_member for the JSON data or an emtpy one if the
202  * member does not exist
203  */
204  [[nodiscard]] constexpr basic_json_value<Range> at( std::string_view key ) {
205  daw::string_view const k = daw::string_view( key.data( ), key.size( ) );
206  std::size_t pos = move_to( k );
207  if( pos < m_locs.size( ) ) {
208  return m_locs[pos].location->value;
209  }
210  return { };
211  }
212 
213  /***
214  * Count the number of elements/members in the JSON class or array
215  * This method is O(N) worst case and O(1) if the locations have already
216  * been determined
217  * @return number of members/elements
218  */
219  [[nodiscard]] std::size_t size( ) {
220  JsonBaseParseTypes const current_type = m_value.type( );
221  switch( current_type ) {
222  case JsonBaseParseTypes::Array:
223  case JsonBaseParseTypes::Class:
224  return move_to( daw::numeric_limits<std::size_t>::max( ) );
225  default:
226  return 0;
227  }
228  }
229 
230  /***
231  * Return the index of named member
232  * This method is O(N) worst case and O(1) if the locations have already
233  * @param key name of member
234  * @return the position of the member or the count of members if not present
235  */
236  [[nodiscard]] std::size_t index_of( std::string_view key ) {
237  daw::string_view const k = daw::string_view( key.data( ), key.size( ) );
238  return move_to( k );
239  }
240 
241  /***
242  * Is the named member present
243  * This method is O(N) worst case and O(1) if the locations have already
244  * @param key name of member
245  * @return true if the member is present
246  */
247  [[nodiscard]] constexpr bool contains( std::string_view key ) {
248  daw::string_view const k = daw::string_view( key.data( ), key.size( ) );
249  return move_to( k ) < m_locs.size( );
250  }
251 
252  /***
253  * Is the indexed member/element present
254  * This method is O(N) worst case and O(1) if the locations have already
255  * @param index position of member/element
256  * @return true if the member/element is present
257  */
258  [[nodiscard]] constexpr bool contains( std::size_t index ) {
259  return move_to( index ) < m_locs.size( );
260  }
261 
262  /***
263  * Get the position of the named member
264  * @tparam Integer An integer type
265  * @param index position of member. If negative it returns the position
266  * from one past last, e.g. -1 is last item
267  * @return The name of the member or an empty optional
268  */
269  template<typename Integer, std::enable_if_t<std::is_integral_v<Integer>,
270  std::nullptr_t> = nullptr>
271  [[nodiscard]] std::optional<std::string_view> name_of( Integer index ) {
272  if constexpr( std::is_signed_v<Integer> ) {
273  if( index < 0 ) {
274  index = -index;
275  auto sz = size( );
276  if( static_cast<std::size_t>( index ) >= sz ) {
277  return { };
278  }
279  sz -= static_cast<std::size_t>( index );
280  return std::string_view( m_locs[sz].name( ).data( ),
281  m_locs[sz].name( ).size( ) );
282  }
283  }
284  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
285  if( pos < m_locs.size( ) ) {
286  return std::string_view( m_locs[pos].name( ).data( ),
287  m_locs[pos].name( ).size( ) );
288  }
289  return { };
290  }
291 
292  /***
293  * basic_json_value for the indexed member
294  * @tparam Integer An integer type
295  * @param index position of member. If negative it returns the position
296  * from one past last, e.g. -1 is last item
297  * @pre index must exist
298  * @return A new basic_json_value for the indexed member
299  */
300  template<typename Integer, std::enable_if_t<std::is_integral_v<Integer>,
301  std::nullptr_t> = nullptr>
302  [[nodiscard]] constexpr basic_json_value<Range>
303  operator[]( Integer index ) {
304  if constexpr( std::is_signed_v<Integer> ) {
305  if( index < 0 ) {
306  index = -index;
307  auto sz = size( );
308  daw_json_assert_weak( ( static_cast<std::size_t>( index ) < sz ),
309  ErrorReason::UnknownMember );
310  sz -= static_cast<std::size_t>( index );
311  return m_locs[sz].location->value;
312  }
313  }
314  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
315  daw_json_assert_weak( pos < m_locs.size( ), ErrorReason::UnknownMember );
316  return m_locs[pos].location->value;
317  }
318 
319  /***
320  * basic_json_value for the indexed member
321  * @tparam Integer An integer type
322  * @param index position of member. If negative it returns the position
323  * from one past last, e.g. -1 is last item
324  * @return A new basic_json_value for the indexed member
325  */
326  template<typename Integer, std::enable_if_t<std::is_integral_v<Integer>,
327  std::nullptr_t> = nullptr>
328  [[nodiscard]] constexpr std::optional<basic_json_value<Range>>
329  at( Integer index ) {
330  if constexpr( std::is_signed_v<Integer> ) {
331  if( index < 0 ) {
332  index = -index;
333  auto sz = size( );
334  if( static_cast<std::size_t>( index ) >= sz ) {
335  return { };
336  }
337  sz -= static_cast<std::size_t>( index );
338  return m_locs[sz].location->value;
339  }
340  }
341  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
342  if( pos < m_locs.size( ) ) {
343  return m_locs[pos].location->value;
344  }
345  return { };
346  }
347 
348  /***
349  * @return A copy of the underlying basic_json_value
350  */
351  [[nodiscard]] constexpr basic_json_value<Range> get_json_value( ) const {
352  return m_value;
353  }
354  };
355 
358 } // namespace daw::json
daw_json_value.h
daw::json::basic_stateful_json_value::basic_stateful_json_value
constexpr basic_stateful_json_value()
Definition: daw_json_value_state.h:157
daw::json::basic_stateful_json_value::operator[]
constexpr basic_json_value< Range > operator[](Integer index)
Definition: daw_json_value_state.h:303
daw::json::basic_stateful_json_value::operator[]
constexpr basic_json_value< Range > operator[](std::string_view key)
Definition: daw_json_value_state.h:178
daw::json::json_member_name::json_member_name
constexpr json_member_name(std::string_view Name)
Definition: daw_json_value_state.h:57
daw::json
Definition: daw_json_event_parser.h:17
daw_json_assert_weak
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:206
daw::json::basic_stateful_json_value::at
constexpr basic_json_value< Range > at(std::string_view key)
Definition: daw_json_value_state.h:204
daw::json::basic_json_value::get_range
constexpr Range get_range() const
Definition: daw_json_value.h:340
daw::json::basic_stateful_json_value::at
constexpr std::optional< basic_json_value< Range > > at(Integer index)
Definition: daw_json_value_state.h:329
daw::json::basic_stateful_json_value::size
std::size_t size()
Definition: daw_json_value_state.h:219
daw::json::basic_stateful_json_value
Definition: daw_json_value_state.h:68
daw::json::basic_stateful_json_value::get_json_value
constexpr basic_json_value< Range > get_json_value() const
Definition: daw_json_value_state.h:351
daw::json::basic_stateful_json_value::contains
constexpr bool contains(std::string_view key)
Definition: daw_json_value_state.h:247
daw::json::basic_stateful_json_value::name_of
std::optional< std::string_view > name_of(Integer index)
Definition: daw_json_value_state.h:271
daw::json::JsonBaseParseTypes
JsonBaseParseTypes
Definition: daw_json_parse_common.h:379
daw::json::basic_stateful_json_value::contains
constexpr bool contains(std::size_t index)
Definition: daw_json_value_state.h:258
daw::json::basic_stateful_json_value::index_of
std::size_t index_of(std::string_view key)
Definition: daw_json_value_state.h:236
daw::name_hash
constexpr UInt32 name_hash(StringView key, std::uint32_t seed=0)
Definition: daw_murmur3.h:43
daw::json::basic_stateful_json_value::reset
constexpr void reset(basic_json_value< Range > val)
Definition: daw_json_value_state.h:166
daw_json_arrow_proxy.h
daw::json::basic_json_value::begin
constexpr iterator begin() const
Definition: daw_json_value.h:349
daw::json::basic_json_value
Definition: daw_json_value.h:300
daw::json::basic_json_value::type
JsonBaseParseTypes type() const
Definition: daw_json_value.h:368
daw_murmur3.h
daw
Definition: daw_json_event_parser.h:17
daw::json::basic_stateful_json_value::operator[]
constexpr basic_json_value< Range > operator[](json_member_name member)
Definition: daw_json_value_state.h:191
daw::json::basic_json_value::end
constexpr iterator end() const
Definition: daw_json_value.h:360
daw_json_parse_name.h
daw::json::json_member_name::name
daw::string_view name
Definition: daw_json_value_state.h:54
daw::json::json_member_name
Definition: daw_json_value_state.h:53
daw::json::json_member_name::hash_value
daw::UInt32 hash_value
Definition: daw_json_value_state.h:55
daw::json::basic_stateful_json_value::basic_stateful_json_value
constexpr basic_stateful_json_value(basic_json_value< Range > val)
Definition: daw_json_value_state.h:145
daw::json::basic_stateful_json_value::basic_stateful_json_value
constexpr basic_stateful_json_value(std::string_view json_data)
Definition: daw_json_value_state.h:160