DAW JSON Link
daw_json_value.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 "daw_json_arrow_proxy.h"
12 #include "daw_json_assert.h"
13 #include "daw_json_parse_name.h"
14 
15 #include <ciso646>
16 #include <cstddef>
17 #include <optional>
18 #include <string_view>
19 #include <tuple>
20 
21 namespace daw::json {
22  /***
23  * A container for arbitrary JSON values
24  * @tparam Range see IteratorRange
25  */
26  template<typename Range>
27  class basic_json_value;
28 
29  /***
30  * A name/value pair of string_view/json_value
31  * @tparam Range see IteratorRange
32  */
33  template<typename Range>
34  struct basic_json_pair {
35  std::optional<std::string_view> name;
37  };
38 
39  template<std::size_t Idx, typename Range>
40  constexpr decltype( auto ) get( basic_json_pair<Range> const &rng ) {
41  static_assert( Idx < 2 );
42  if constexpr( Idx == 0 ) {
43  return rng.name;
44  } else {
45  return rng.value;
46  }
47  }
48 
49  template<std::size_t Idx, typename Range>
50  constexpr decltype( auto ) get( basic_json_pair<Range> &rng ) {
51  static_assert( Idx < 2 );
52  if constexpr( Idx == 0 ) {
53  return rng.name;
54  } else {
55  return rng.value;
56  }
57  }
58 
59  template<std::size_t Idx, typename Range>
60  constexpr decltype( auto ) get( basic_json_pair<Range> &&rng ) {
61  static_assert( Idx < 2 );
62  if constexpr( Idx == 0 ) {
63  return std::move( rng.name );
64  } else {
65  return std::move( rng.value );
66  }
67  }
68 } // namespace daw::json
69 
70 namespace std {
71  template<typename Range>
72  class tuple_element<0, daw::json::basic_json_pair<Range>> {
73  public:
74  using type = std::optional<std::string_view>;
75  };
76 
77  template<typename Range>
78  class tuple_element<1, daw::json::basic_json_pair<Range>> {
79  public:
81  };
82 
83  template<typename Range>
84  class tuple_size<daw::json::basic_json_pair<Range>>
85  : public std::integral_constant<std::size_t, 2> {};
86 } // namespace std
87 
88 namespace daw::json {
89  /***
90  * Iterator for iterating over arbutrary JSON members and array elements
91  * @tparam Range see IteratorRange
92  */
93  template<typename Range>
95  using key_type = std::string_view;
97 
101  using pointer = json_details::arrow_proxy<value_type>;
102  using difference_type = std::ptrdiff_t;
103  using iterator_category = std::forward_iterator_tag;
104 
105  private:
106  Range m_state{ };
107 
108  constexpr basic_json_value_iterator( Range rng )
109  : m_state( rng ) {}
110 
111  friend class ::daw::json::basic_json_value<Range>;
112 
113  public:
114  constexpr basic_json_value_iterator( ) = default;
115 
116  /***
117  * Name of member
118  * @return The name, if any, of the current member
119  */
120  constexpr std::optional<std::string_view> name( ) const {
121  if( is_array( ) ) {
122  return { };
123  }
124  auto rng = m_state;
125  auto result = json_details::parse_name( rng );
126  return std::string_view( result.data( ), result.size( ) );
127  }
128 
129  /***
130  * Get the value currently being referenced
131  * @return A basic_json_value representing the currently referenced element
132  * in the range
133  */
134  [[nodiscard]] constexpr basic_json_value<Range> value( ) const {
135  if( is_array( ) ) {
136  return Range( m_state );
137  }
138  auto rng = m_state;
139  (void)json_details::parse_name( rng );
140  return Range( rng.first, rng.last );
141  }
142 
143  /***
144  * Get the name/value pair of the currently referenced element
145  * @return a json_pair with the name, if any, and json_value
146  */
147  [[nodiscard]] constexpr basic_json_pair<Range> operator*( ) {
148  if( is_array( ) ) {
149  return { { }, Range( m_state.first, m_state.last ) };
150  }
151  auto rng = m_state;
152  auto name = json_details::parse_name( rng );
153  return { std::string_view( name.data( ), name.size( ) ),
154  Range( rng.first, rng.last ) };
155  }
156 
157  /***
158  * Return an arrow_proxy object containing the result of operator*
159  * Should not use this method unless you must(std algorithms), it is here
160  * for Iterator compatibility
161  * @return arrow_proxy object containing the result of operator*
162  */
163  [[nodiscard]] constexpr pointer operator->( ) {
164  return { operator*( ) };
165  }
166 
167  /***
168  * Move the parser to the next value
169  * @return A reference to the iterator
170  */
172  if( good( ) ) {
173  if( is_class( ) ) {
174  (void)json_details::parse_name( m_state );
175  }
176  (void)json_details::skip_value( m_state );
177  m_state.clean_tail( );
178  }
179  return *this;
180  }
181 
182  /***
183  * Moved parser to next value
184  * @return copy of iterator upon entering method
185  */
187  auto result = *this;
188  operator++( );
189  return result;
190  }
191 
192  /***
193  * Is the value this iterator iterates over an array
194  * @return true if the value is an array
195  */
196  [[nodiscard]] constexpr bool is_array( ) const {
197  return *m_state.class_first == '[';
198  }
199 
200  /***
201  * Is the value this iterator iterates over an class
202  * @return true if the value is an class
203  */
204  [[nodiscard]] constexpr bool is_class( ) const {
205  return *m_state.class_first == '{';
206  }
207 
208  /***
209  * Can we increment more
210  * @return True if safe to increment more
211  */
212  constexpr bool good( ) const {
213  if( not m_state.has_more( ) or m_state.is_null( ) ) {
214  return false;
215  }
216  switch( m_state.front( ) ) {
217  case '[':
218  case '{':
219  case '"':
220  case '-':
221  case '0':
222  case '1':
223  case '2':
224  case '3':
225  case '4':
226  case '5':
227  case '6':
228  case '7':
229  case '8':
230  case '9':
231  case 't':
232  case 'f':
233  case 'n':
234  return true;
235  case '}':
236  case ']':
237  return false;
238  }
239  daw_json_error( ErrorReason::ExpectedTokenNotFound, m_state );
240  }
241 
242  /***
243  * Can we increment more
244  * @return True if safe to increment more
245  */
246  constexpr explicit operator bool( ) const {
247  return good( );
248  }
249 
250  /***
251  * Check for equivilence with rhs iterator
252  * @param rhs iterator to compare for equivilence with
253  * @return true if both are equivilent
254  */
255  constexpr bool
257  if( good( ) ) {
258  if( rhs.good( ) ) {
259  return m_state.first == rhs.m_state.first;
260  }
261  return false;
262  }
263  return not rhs.good( );
264  }
265 
266  /***
267  * Check if rhs is not equivilent to self
268  * @param rhs iterator to compare for equivilence with
269  * @return true if the rhs is not equivilent
270  */
271  constexpr bool
273  return not operator==( rhs );
274  }
275  };
276 
277  template<typename Range>
282 
283  constexpr iterator begin( ) {
284  return first;
285  }
286  constexpr iterator end( ) {
287  return last;
288  }
289  };
290  template<typename Range>
294 
295  /***
296  * A container for arbitrary JSON values
297  * @tparam Range see IteratorRange
298  */
299  template<typename Range>
301  Range m_rng{ };
302 
303  public:
305 
306  /***
307  * Construct from IteratorRange
308  * @param rng string data where start is the start of our value
309  */
310  inline constexpr basic_json_value( Range rng )
311  : m_rng( std::move( rng ) ) {
312  // Ensure we are at the actual value
313  m_rng.trim_left( );
314  }
315 
316  /***
317  * Construct from std::string_view
318  */
319  explicit inline constexpr basic_json_value( std::string_view sv )
320  : m_rng( sv.data( ), sv.data( ) + sv.size( ) ) {}
321 
322  /***
323  * Construct from char const *, std::size_t
324  */
325  explicit inline constexpr basic_json_value( char const *first,
326  std::size_t sz )
327  : m_rng( first, first + static_cast<std::ptrdiff_t>( sz ) ) {}
328 
329  /***
330  * Construct from char const *, char const *
331  */
332  explicit inline constexpr basic_json_value( char const *first,
333  char const *last )
334  : m_rng( first, last ) {}
335 
336  /***
337  * Get a copy of the underlying range
338  * @return IteratorRange containing values JSON data
339  */
340  [[nodiscard]] inline constexpr Range get_range( ) const {
341  return m_rng;
342  }
343 
344  /***
345  * Get the first member/item
346  * @pre type of value is class or array
347  * @return basic_json_value_iterator to the first item/member
348  */
349  [[nodiscard]] inline constexpr iterator begin( ) const {
350  Range rng = Range( m_rng.first, m_rng.last );
351  rng.remove_prefix( );
352  rng.trim_left( );
353  return basic_json_value_iterator<Range>( rng );
354  }
355 
356  /***
357  * End of range over class/arrays members/items
358  * @return default constructed basic_json_value_iterator
359  */
360  [[nodiscard]] inline constexpr iterator end( ) const {
362  }
363 
364  /***
365  * Get the type of JSON value
366  * @return a JSONBaseParseTypes enum value with the type of this JSON value
367  */
368  [[nodiscard]] JsonBaseParseTypes type( ) const {
369  if( not m_rng.has_more( ) ) {
371  }
372  switch( m_rng.front( ) ) {
373  case '"':
374  return JsonBaseParseTypes::String;
375  case '{':
376  return JsonBaseParseTypes::Class;
377  case '[':
378  return JsonBaseParseTypes::Array;
379  case '-':
380  case '0':
381  case '1':
382  case '2':
383  case '3':
384  case '4':
385  case '5':
386  case '6':
387  case '7':
388  case '8':
389  case '9':
390  return JsonBaseParseTypes::Number;
391  case 't':
392  if constexpr( not Range::is_unchecked_input ) {
393  if( m_rng.starts_with( "true" ) ) {
394  return JsonBaseParseTypes::Bool;
395  }
397  } else {
398  return JsonBaseParseTypes::Bool;
399  }
400  case 'f':
401  if constexpr( not Range::is_unchecked_input ) {
402  if( m_rng.starts_with( "false" ) ) {
403  return JsonBaseParseTypes::Bool;
404  }
406  } else {
407  return JsonBaseParseTypes::Bool;
408  }
409  case 'n':
410  daw_json_assert_weak( m_rng.starts_with( "null" ),
411  ErrorReason::InvalidNull, m_rng );
412  return JsonBaseParseTypes::Null;
413  }
415  }
416 
417  /***
418  * Get the JSON data
419  * @return the JSON data as a std::string_view
420  */
421  constexpr std::string_view get_string_view( ) const {
422  auto rng = m_rng;
423  auto result = json_details::skip_value( rng );
424  if( is_string( ) ) {
425  --result.first;
426  ++result.last;
427  }
428  return { result.first, result.size( ) };
429  }
430 
431  /***
432  * Get a copy of the JSON data
433  * @return the JSON data as a std::string
434  */
435  template<typename Allocator = std::allocator<char>,
436  typename Traits = std::char_traits<char>>
437  std::basic_string<char, Traits, Allocator>
438  get_string( Allocator const &alloc = std::allocator<char>( ) ) const {
439  auto rng = m_rng;
440  auto result = json_details::skip_value( rng );
441  if( is_string( ) ) {
442  --result.first;
443  ++result.last;
444  }
445  return { result.first, result.size( ), alloc };
446  }
447 
448  /***
449  * Is the JSON value a null literal
450  * @return true if the value is a null literal
451  */
452  constexpr bool is_null( ) const {
453  return ( m_rng.starts_with( "null" ) );
454  }
455 
456  /***
457  * Is the JSON value a class
458  * @return true if the value is a class
459  */
460  constexpr bool is_class( ) const {
461  return m_rng.is_opening_brace_checked( );
462  }
463 
464  /***
465  * Is the JSON value a array
466  * @return true if the value is a array
467  */
468  constexpr bool is_array( ) const {
469  return m_rng.is_opening_bracket_checked( );
470  }
471 
472  /***
473  * Is the JSON value a number literal
474  * @return true if the value is a number literal
475  */
476  constexpr bool is_number( ) const {
477  if( not m_rng.has_more( ) ) {
478  return false;
479  }
480  switch( m_rng.front( ) ) {
481  case '0':
482  case '1':
483  case '2':
484  case '3':
485  case '4':
486  case '5':
487  case '6':
488  case '7':
489  case '8':
490  case '9':
491  case '+':
492  case '-':
493  return true;
494  }
495  return false;
496  }
497 
498  /***
499  * Is the JSON value a string
500  * @return true if the value is a string
501  */
502  inline constexpr bool is_string( ) const {
503  return m_rng.is_quotes_checked( );
504  }
505 
506  /***
507  * Is the JSON value a boolean
508  * @return true if the value is a boolean
509  */
510  constexpr bool is_bool( ) const {
511  if( not m_rng.has_more( ) ) {
512  return false;
513  }
514  switch( m_rng.front( ) ) {
515  case 't':
516  if constexpr( not Range::is_unchecked_input ) {
517  return m_rng == "true";
518  } else {
519  return true;
520  }
521  case 'f':
522  if constexpr( not Range::is_unchecked_input ) {
523  return m_rng == "false";
524  } else {
525  return true;
526  }
527  }
528  return false;
529  }
530 
531  /***
532  * Is the JSON data unrecognizable. JSON members will start with one of
533  * ",[,{,0,1,2,3,4,5,6,7,8,9,-,t,f, or n and this does not
534  * @return true if the parser is unsure what the data is
535  */
536  inline constexpr bool is_unknown( ) const {
537  return type( ) == JsonBaseParseTypes::None;
538  }
539 
540  template<typename NewRange>
541  explicit inline constexpr operator basic_json_value<NewRange>( ) const {
542  auto new_range = NewRange( m_rng.first, m_rng.last );
543  new_range.class_first = m_rng.class_first;
544  new_range.class_last = m_rng.class_last;
545  return basic_json_value<NewRange>( std::move( new_range ) );
546  }
547  };
548 } // namespace daw::json
daw::json::basic_json_pair
Definition: daw_json_value.h:34
daw::json::get
constexpr decltype(auto) get(basic_json_pair< Range > const &rng)
Definition: daw_json_value.h:40
daw::json::basic_json_value_iterator_range::first
iterator first
Definition: daw_json_value.h:280
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_json_value::basic_json_value
constexpr basic_json_value(char const *first, std::size_t sz)
Definition: daw_json_value.h:325
daw::json::basic_json_value_iterator::operator->
constexpr pointer operator->()
Definition: daw_json_value.h:163
daw::json::basic_json_value::get_range
constexpr Range get_range() const
Definition: daw_json_value.h:340
daw::json::JsonBaseParseTypes
JsonBaseParseTypes
Definition: daw_json_parse_common.h:379
daw::json::basic_json_pair::name
std::optional< std::string_view > name
Definition: daw_json_value.h:35
daw_json_error
static DAW_JSON_NOINLINE void daw_json_error(daw::json::ErrorReason reason)
Definition: daw_json_assert.h:59
daw::json::basic_json_value_iterator::name
constexpr std::optional< std::string_view > name() const
Definition: daw_json_value.h:120
daw::json::basic_json_value::basic_json_value
constexpr basic_json_value(std::string_view sv)
Definition: daw_json_value.h:319
daw::json::basic_json_value_iterator::key_type
std::string_view key_type
Definition: daw_json_value.h:95
daw_json_arrow_proxy.h
daw::json::basic_json_value_iterator::operator++
constexpr basic_json_value_iterator operator++(int)
Definition: daw_json_value.h:186
daw::json::basic_json_value_iterator::operator!=
constexpr bool operator!=(basic_json_value_iterator< Range > const &rhs) const
Definition: daw_json_value.h:272
daw::json::basic_json_value_iterator::difference_type
std::ptrdiff_t difference_type
Definition: daw_json_value.h:102
daw::json::basic_json_value::get_string_view
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:421
daw::json::basic_json_value::begin
constexpr iterator begin() const
Definition: daw_json_value.h:349
daw::json::JsonBaseParseTypes::Number
@ Number
daw::json::basic_json_value
Definition: daw_json_value.h:300
daw::json::basic_json_value_iterator::operator==
constexpr bool operator==(basic_json_value_iterator< Range > const &rhs) const
Definition: daw_json_value.h:256
daw::json::basic_json_value_iterator::is_class
constexpr bool is_class() const
Definition: daw_json_value.h:204
daw::json::basic_json_value::is_bool
constexpr bool is_bool() const
Definition: daw_json_value.h:510
daw::json::basic_json_value_iterator::iterator_category
std::forward_iterator_tag iterator_category
Definition: daw_json_value.h:103
daw::json::basic_json_value_iterator_range::last
iterator last
Definition: daw_json_value.h:281
daw::json::basic_json_value_iterator::operator++
constexpr basic_json_value_iterator & operator++()
Definition: daw_json_value.h:171
daw::json::basic_json_value::is_null
constexpr bool is_null() const
Definition: daw_json_value.h:452
daw::json::basic_json_value_iterator::basic_json_value_iterator
constexpr basic_json_value_iterator()=default
daw::json::basic_json_value::basic_json_value
constexpr basic_json_value(char const *first, char const *last)
Definition: daw_json_value.h:332
daw::json::basic_json_value_iterator_range
basic_json_value_iterator_range(basic_json_value_iterator< Range >, basic_json_value_iterator< Range >) -> basic_json_value_iterator_range< Range >
daw::json::basic_json_value::type
JsonBaseParseTypes type() const
Definition: daw_json_value.h:368
daw::json::basic_json_value::basic_json_value
constexpr basic_json_value(Range rng)
Definition: daw_json_value.h:310
daw
Definition: daw_json_event_parser.h:17
daw::json::basic_json_value_iterator_range::begin
constexpr iterator begin()
Definition: daw_json_value.h:283
daw::json::basic_json_pair::value
basic_json_value< Range > value
Definition: daw_json_value.h:36
daw_json_assert.h
daw::json::basic_json_value_iterator::pointer
json_details::arrow_proxy< value_type > pointer
Definition: daw_json_value.h:101
daw::json::basic_json_value_iterator_range
Definition: daw_json_value.h:278
daw::json::basic_json_value_iterator::good
constexpr bool good() const
Definition: daw_json_value.h:212
daw::json::basic_json_value::is_string
constexpr bool is_string() const
Definition: daw_json_value.h:502
daw::json::basic_json_value_iterator::operator*
constexpr basic_json_pair< Range > operator*()
Definition: daw_json_value.h:147
daw::json::basic_json_value::is_array
constexpr bool is_array() const
Definition: daw_json_value.h:468
daw::json::basic_json_value::end
constexpr iterator end() const
Definition: daw_json_value.h:360
daw_json_parse_name.h
daw::json::basic_json_value_iterator::is_array
constexpr bool is_array() const
Definition: daw_json_value.h:196
daw::json::basic_json_value_iterator
Definition: daw_json_value.h:94
daw::json::basic_json_value_iterator::value_type
basic_json_pair< Range > value_type
Definition: daw_json_value.h:99
daw::json::basic_json_value_iterator::value
constexpr basic_json_value< Range > value() const
Definition: daw_json_value.h:134
daw::json::basic_json_value::get_string
std::basic_string< char, Traits, Allocator > get_string(Allocator const &alloc=std::allocator< char >()) const
Definition: daw_json_value.h:438
daw::json::basic_json_value::is_unknown
constexpr bool is_unknown() const
Definition: daw_json_value.h:536
daw::json::basic_json_value_iterator_range::end
constexpr iterator end()
Definition: daw_json_value.h:286
daw::json::basic_json_value::is_class
constexpr bool is_class() const
Definition: daw_json_value.h:460
daw::json::basic_json_value::is_number
constexpr bool is_number() const
Definition: daw_json_value.h:476