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