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