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 
11 #include "impl/version.h"
12 
16 #include "impl/daw_json_value.h"
17 #include "impl/daw_murmur3.h"
18 
19 #include <daw/daw_move.h>
20 #include <daw/daw_string_view.h>
21 #include <daw/daw_uint_buffer.h>
22 
23 #include <cstddef>
24 #include <string_view>
25 #include <utility>
26 #include <vector>
27 
28 namespace daw::json {
29  inline namespace DAW_JSON_VER {
30  namespace json_details {
31  template<json_options_t PolicyFlags = default_policy_flag,
32  typename Allocator = NoAllocator>
33  class basic_stateful_json_value_state {
34  using ParseState =
36 
37  public:
38  daw::string_view name;
39  daw::UInt32 hash_value;
41 
42  explicit constexpr basic_stateful_json_value_state(
43  daw::string_view Name,
45  : name( Name )
46  , hash_value(
47  daw::name_hash<ParseState::expect_long_strings>( Name ) )
48  , location( std::move( val ) ) {}
49 
50  [[nodiscard]] constexpr bool is_match( daw::string_view Name ) const {
51  return name == Name;
52  }
53 
54  [[nodiscard]] constexpr bool is_match( daw::string_view Name,
55  daw::UInt32 hash ) const {
56  if( hash != hash_value ) {
57  return false;
58  }
59  return name == Name;
60  }
61  };
62  } // namespace json_details
63 
65  daw::string_view name;
66  daw::UInt32 hash_value;
67 
68  constexpr json_member_name( std::string_view Name )
69  : name( std::data( Name ), std::size( Name ) )
70  , hash_value( daw::name_hash<false>( name ) ) {}
71  };
72 
78  template<json_options_t PolicyFlags = json_details::default_policy_flag,
79  typename Allocator = json_details::NoAllocator>
81  using ParseState =
83 
85  std::vector<
86  json_details::basic_stateful_json_value_state<PolicyFlags, Allocator>>
87  m_locs{ };
88 
89  /***
90  * Move parser until member name matches key if needed
91  * @param member to move_to
92  * @return position of member or size
93  */
94  [[nodiscard]] constexpr std::size_t move_to( json_member_name member ) {
95  std::size_t pos = 0;
96  std::size_t const Sz = std::size( m_locs );
97  for( ; pos < Sz; ++pos ) {
98  if( m_locs[pos].is_match( member.name, member.hash_value ) ) {
99  return pos;
100  }
101  }
102 
103  auto it = [&] {
104  if( m_locs.empty( ) ) {
105  return m_value.begin( );
106  }
107  auto res = m_locs.back( ).location;
108  ++res;
109  return res;
110  }( );
111  auto const last = m_value.end( );
112  while( it != last ) {
113  auto name = it.name( );
114  daw_json_assert_weak( name, ErrorReason::MissingMemberName );
115  auto const &new_loc = m_locs.emplace_back(
116  daw::string_view( std::data( *name ), std::size( *name ) ), it );
117  if( new_loc.is_match( member.name ) ) {
118  return pos;
119  }
120  ++pos;
121  ++it;
122  }
123  return std::size( m_locs );
124  }
125 
126  /***
127  * Move parser until member index matches, if needed
128  * @param index position of member to move to
129  * @return position in members or size
130  */
131  [[nodiscard]] constexpr std::size_t move_to( std::size_t index ) {
132  if( index < std::size( m_locs ) ) {
133  return index;
134  }
135  auto it = [&] {
136  if( m_locs.empty( ) ) {
137  return m_value.begin( );
138  }
139  auto res = m_locs.back( ).location;
140  ++res;
141  return res;
142  }( );
143  auto last = m_value.end( );
144  std::size_t pos = std::size( m_locs );
145  while( it != last ) {
146  auto name = it.name( );
147  if( name ) {
148  m_locs.emplace_back(
149  daw::string_view( std::data( *name ), std::size( *name ) ), it );
150  } else {
151  m_locs.emplace_back( daw::string_view( ), it );
152  }
153  if( pos == index ) {
154  return pos;
155  }
156  ++pos;
157  ++it;
158  }
159  return std::size( m_locs );
160  }
161 
162  public:
165  : m_value( std::move( val ) ) {
166 
167  daw_json_assert_weak( ( [&] {
168  auto t = m_value.type( );
169  return ( t == JsonBaseParseTypes::Class ) |
170  ( t == JsonBaseParseTypes::Array );
171  }( ) ),
172  ErrorReason::ExpectedArrayOrClassStart,
173  val.get_raw_state( ) );
174  }
175 
178  basic_json_value<PolicyFlags, Allocator>( "{}" ) ) {}
179 
180  constexpr basic_stateful_json_value( daw::string_view json_data )
182  basic_json_value<PolicyFlags, Allocator>( json_data ) ) {}
187  constexpr void reset( basic_json_value<PolicyFlags, Allocator> val ) {
188  m_value = std::move( val );
189  m_locs.clear( );
190  }
191 
197  [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
198  operator[]( std::string_view key ) {
199  std::size_t pos = move_to( json_member_name( key ) );
200  daw_json_assert_weak( pos < std::size( m_locs ),
201  ErrorReason::UnknownMember );
202  return m_locs[pos].location->value;
203  }
204 
210  [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
212  std::size_t pos = move_to( member );
213  daw_json_assert_weak( pos < std::size( m_locs ),
214  ErrorReason::UnknownMember );
215  return m_locs[pos].location->value;
216  }
217 
223  [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
224  at( std::string_view key ) {
225  auto const k = std::string_view( std::data( key ), std::size( key ) );
226  std::size_t pos = move_to( k );
227  if( pos < std::size( m_locs ) ) {
228  return m_locs[pos].location->value;
229  }
230  return { };
231  }
232 
238  [[nodiscard]] std::size_t size( ) {
239  JsonBaseParseTypes const current_type = m_value.type( );
240  switch( current_type ) {
241  case JsonBaseParseTypes::Array:
242  case JsonBaseParseTypes::Class:
243  return move_to( ( daw::numeric_limits<std::size_t>::max )( ) );
244  case JsonBaseParseTypes::Number:
245  case JsonBaseParseTypes::Bool:
246  case JsonBaseParseTypes::String:
247  case JsonBaseParseTypes::Null:
248  case JsonBaseParseTypes::None:
249  default:
250  return 0;
251  }
252  }
253 
260  [[nodiscard]] std::size_t index_of( std::string_view key ) {
261  auto const k = json_member_name( key );
262  return move_to( k );
263  }
264 
270  [[nodiscard]] constexpr bool contains( std::string_view key ) {
271  auto const k = std::string_view( std::data( key ), std::size( key ) );
272  return move_to( k ) < std::size( m_locs );
273  }
274 
275  /***
276  * Is the indexed member/element present
277  * This method is O(N) worst case and O(1) if the locations have already
278  * @param index position of member/element
279  * @return true if the member/element is present
280  */
281  [[nodiscard]] constexpr bool contains( std::size_t index ) {
282  return move_to( index ) < size( m_locs );
283  }
284 
285  /***
286  * Get the position of the named member
287  * @tparam Integer An integer type
288  * @param index position of member. If negative it returns the position
289  * from one past last, e.g. -1 is last item
290  * @return The name of the member or an empty optional
291  */
292  template<typename Integer>
293  [[nodiscard]] std::optional<std::string_view> name_of( Integer index ) {
294  static_assert( std::is_integral_v<Integer>,
295  "Only integer indices are allowed" );
296  if constexpr( std::is_signed_v<Integer> ) {
297  if( index < 0 ) {
298  index = -index;
299  auto sz = size( );
300  if( static_cast<std::size_t>( index ) >= sz ) {
301  return { };
302  }
303  sz -= static_cast<std::size_t>( index );
304  return std::string_view( std::data( m_locs[sz].name( ) ),
305  std::size( m_locs[sz].name( ) ) );
306  }
307  }
308  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
309  if( pos < std::size( m_locs ) ) {
310  return std::string_view( std::data( m_locs[pos].name( ) ),
311  std::size( m_locs[pos].name( ) ) );
312  }
313  return { };
314  }
315 
316  /***
317  * basic_json_value for the indexed member
318  * @tparam Integer An integer type
319  * @param index position of member. If negative it returns the position
320  * from one past last, e.g. -1 is last item
321  * @pre index must exist
322  * @return A new basic_json_value for the indexed member
323  */
324  template<
325  typename Integer DAW_JSON_ENABLEIF( std::is_integral_v<Integer> )>
326  DAW_JSON_REQUIRES( std::is_integral_v<Integer> )
327  [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
328  operator[]( Integer index ) {
329  if constexpr( std::is_signed_v<Integer> ) {
330  if( index < 0 ) {
331  index = -index;
332  auto sz = size( );
333  daw_json_assert_weak( ( static_cast<std::size_t>( index ) < sz ),
334  ErrorReason::UnknownMember );
335  sz -= static_cast<std::size_t>( index );
336  return m_locs[sz].location->value;
337  }
338  }
339  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
340  daw_json_assert_weak( pos < std::size( m_locs ),
341  ErrorReason::UnknownMember );
342  return m_locs[pos].location->value;
343  }
344 
345  /***
346  * basic_json_value for the indexed member
347  * @tparam Integer An integer type
348  * @param index position of member. If negative it returns the position
349  * from one past last, e.g. -1 is last item
350  * @return A new basic_json_value for the indexed member
351  */
352  template<
353  typename Integer DAW_JSON_ENABLEIF( std::is_integral_v<Integer> )>
354  DAW_JSON_REQUIRES( std::is_integral_v<Integer> )
355  [[nodiscard]] constexpr std::optional<
357  if constexpr( std::is_signed_v<Integer> ) {
358  if( index < 0 ) {
359  index = -index;
360  auto sz = size( );
361  if( static_cast<std::size_t>( index ) >= sz ) {
362  return { };
363  }
364  sz -= static_cast<std::size_t>( index );
365  return m_locs[sz].location->value( );
366  }
367  }
368  std::size_t pos = move_to( static_cast<std::size_t>( index ) );
369  if( pos < std::size( m_locs ) ) {
370  return m_locs[pos].location->value( );
371  }
372  return { };
373  }
374 
375  /***
376  * @return A copy of the underlying basic_json_value
377  */
378  [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
379  get_json_value( ) const {
380  return m_value;
381  }
382  };
383 
385 
386  template<json_options_t PolicyFlags, typename Allocator>
389 
390  basic_stateful_json_value( daw::string_view )
392 
394  } // namespace DAW_JSON_VER
395 } // namespace daw::json
constexpr basic_json_value< PolicyFlags, Allocator > operator[](std::string_view key)
Create a basic_json_member for the named member.
std::size_t index_of(std::string_view key)
Return the index of named member. This method is O(N) worst case and O(1) if the locations have alrea...
constexpr basic_json_value< PolicyFlags, Allocator > at(std::string_view key)
Create a basic_json_member for the named member.
constexpr basic_json_value< PolicyFlags, Allocator > operator[](json_member_name member)
Create a basic_json_member for the named member.
constexpr std::optional< basic_json_value< PolicyFlags, Allocator > > at(Integer index)
std::size_t size()
Count the number of elements/members in the JSON class or array This method is O(N) worst case and O(...
constexpr basic_json_value< PolicyFlags, Allocator > get_json_value() const
TryDefaultParsePolicy< BasicParsePolicy< PolicyFlags, Allocator > > ParseState
constexpr basic_json_value< PolicyFlags, Allocator > operator[](Integer index)
#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_ENABLEIF(...)
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
basic_stateful_json_value() -> basic_stateful_json_value<>
Customization point traits.
DAW_JSON_REQUIRES(boost::describe::has_describe_members< T >::value and use_boost_describe_v< T >) struct json_data_contract< T >
static constexpr DAW_ATTRIB_INLINE UInt32 name_hash(daw::string_view key)
Definition: daw_murmur3.h:74
Iterator for iterating over arbitrary JSON members and array elements.
constexpr std::optional< std::string_view > name() const
Name of member.
A non-owning container for arbitrary JSON values that allows movement/iteration through.
constexpr iterator end() const
End of range over class/arrays members/items.
constexpr iterator begin() const
Get the first member/item.
constexpr ParseState get_raw_state() const
Get a copy of the underlying parse state.
constexpr JsonBaseParseTypes type() const
Get the type of JSON value.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25