DAW JSON Link
Loading...
Searching...
No Matches
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
12
24
25#include <daw/daw_algorithm.h>
26#include <daw/daw_attributes.h>
27#include <daw/daw_move.h>
28#include <daw/daw_utility.h>
29
30#include <cassert>
31#include <cstddef>
32#include <daw/stdinc/tuple_traits.h>
33#include <optional>
34#include <string_view>
35
36namespace daw::json {
37 inline namespace DAW_JSON_VER {
40 template<json_options_t PolicyFlags = json_details::default_policy_flag,
41 typename Allocator = json_details::NoAllocator>
49
50 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
51 constexpr decltype( auto )
53 static_assert(
54 Idx < 2,
55 "Invalid index. Valid values are 0 for name, and 1 for value" );
56 if constexpr( Idx == 0 ) {
57 return parse_state.name;
58 } else {
59 return parse_state.value;
60 }
61 }
62
63 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
64 constexpr decltype( auto )
66 static_assert(
67 Idx < 2,
68 "Invalid index. Valid values are 0 for name, and 1 for value" );
69 if constexpr( Idx == 0 ) {
70 return parse_state.name;
71 } else {
72 return parse_state.value;
73 }
74 }
75
76 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
77 constexpr decltype( auto )
79 static_assert(
80 Idx < 2,
81 "Invalid index. Valid values are 0 for name, and 1 for value" );
82 if constexpr( Idx == 0 ) {
83 return std::move( parse_state.name );
84 } else {
85 return std::move( parse_state.value );
86 }
87 }
88 } // namespace DAW_JSON_VER
89} // namespace daw::json
90
91namespace std {
92 template<daw::json::json_options_t PolicyFlags, typename Allocator>
93 class tuple_element<0, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
94 public:
95 using type = std::optional<std::string_view>;
96 };
97
98 template<daw::json::json_options_t PolicyFlags, typename Allocator>
99 class tuple_element<1, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
100 public:
102 };
103
104 template<daw::json::json_options_t PolicyFlags, typename Allocator>
105 class tuple_size<daw::json::basic_json_pair<PolicyFlags, Allocator>> {
106 public:
107 static constexpr std::size_t value = 2;
108 };
109} // namespace std
110
111namespace daw::json {
112 inline namespace DAW_JSON_VER {
116 template<json_options_t PolicyFlags = json_details::default_policy_flag,
117 typename Allocator = json_details::NoAllocator>
119 using key_type = std::string_view;
121
125 using pointer = json_details::arrow_proxy<value_type>;
126 using difference_type = std::ptrdiff_t;
127 using iterator_category = std::forward_iterator_tag;
130
131 private:
133 ParseState m_state{ };
134
135 public:
136 explicit basic_json_value_iterator( ) = default;
137
138 explicit constexpr basic_json_value_iterator(
139 parse_policy const &parse_state )
140 : m_state( parse_state ) {}
141
142 explicit basic_json_value_iterator( daw::string_view json_doc )
143 : m_state( std::data( json_doc ), daw::data_end( json_doc ) ) {}
144
145 explicit basic_json_value_iterator( daw::string_view json_doc,
146 Allocator const &alloc )
147 : m_state( std::data( json_doc ), daw::data_end( json_doc ),
148 std::data( json_doc ), daw::data_end( json_doc ), alloc ) {}
149
152 : m_state( jv.get_raw_state( ) ) {}
153
156 [[nodiscard]] constexpr std::optional<std::string_view> name( ) const {
157 if( is_array( ) ) {
158 return { };
159 }
160 auto parse_state = m_state;
161 auto result = json_details::parse_name( parse_state );
162 return std::string_view( std::data( result ), std::size( result ) );
163 }
164
168 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
169 value( ) const {
170 if( is_array( ) ) {
171 return ParseState( m_state );
172 }
173 auto parse_state = m_state;
174 (void)json_details::parse_name( parse_state );
175 return ParseState( parse_state.first,
176 parse_state.last,
177 parse_state.first,
178 parse_state.last,
179 parse_state.get_allocator( ) );
180 }
181
184 [[nodiscard]] constexpr basic_json_pair<PolicyFlags, Allocator>
186 if( is_array( ) ) {
187 return { { },
188 basic_json_value( ParseState( m_state.first,
189 m_state.last,
190 m_state.first,
191 m_state.last,
192 m_state.get_allocator( ) ) ) };
193 }
194 auto parse_state = m_state;
195 auto name = json_details::parse_name( parse_state );
196 return {
197 std::string_view( std::data( name ), std::size( name ) ),
198 basic_json_value( ParseState( parse_state.first,
199 parse_state.last,
200 parse_state.first,
201 parse_state.last,
202 parse_state.get_allocator( ) ) ) };
203 }
204
209 [[nodiscard]] constexpr pointer operator->( ) {
210 return { operator*( ) };
211 }
212
216 if( good( ) ) {
217 if( is_class( ) ) {
218 (void)json_details::parse_name( m_state );
219 }
220 (void)json_details::skip_value( m_state );
221 m_state.move_next_member_or_end( );
222 }
223 return *this;
224 }
225
227 constexpr void operator++( int ) & {
228 operator++( );
229 }
230
233 [[nodiscard]] constexpr bool is_array( ) const {
234 return *m_state.class_first == '[';
235 }
236
239 [[nodiscard]] constexpr bool is_class( ) const {
240 return *m_state.class_first == '{';
241 }
242
245 [[nodiscard]] constexpr bool good( ) const {
246 if( m_state.is_null( ) or not m_state.has_more( ) ) {
247 return false;
248 }
249 switch( m_state.front( ) ) {
250 case '[':
251 case '{':
252 case '"':
253 case '-':
254 case '0':
255 case '1':
256 case '2':
257 case '3':
258 case '4':
259 case '5':
260 case '6':
261 case '7':
262 case '8':
263 case '9':
264 case 't':
265 case 'f':
266 case 'n':
267 return true;
268 case '}':
269 case ']':
270 return false;
271 default:
272 DAW_UNLIKELY_BRANCH
273 daw_json_error( true, ErrorReason::ExpectedTokenNotFound, m_state );
274 }
275 }
276
279 [[nodiscard]] constexpr explicit operator bool( ) const {
280 return good( );
281 }
282
285 [[nodiscard]] constexpr parse_policy const &get_raw_state( ) const {
286 return m_state;
287 }
288
292 template<json_options_t P, typename A>
293 [[nodiscard]] constexpr bool
295 if( good( ) ) {
296 if( rhs.good( ) ) {
297 return m_state.first == rhs.m_state.first;
298 }
299 return false;
300 }
301 return not rhs.good( );
302 }
303
307 template<json_options_t P, typename A>
308 [[nodiscard]] constexpr bool
310 return not operator==( rhs );
311 }
312 };
313
314 template<json_options_t PolicyFlags, typename Allocator>
318
319 basic_json_value_iterator( daw::string_view )
321
322 template<typename Allocator>
323 basic_json_value_iterator( daw::string_view, Allocator const & )
324 -> basic_json_value_iterator<daw::json::json_details::default_policy_flag,
325 Allocator>;
326
327 template<json_options_t PolicyFlags, typename Allocator>
331
334 template<json_options_t PolicyFlags = json_details::default_policy_flag,
335 typename Allocator = json_details::NoAllocator>
340
341 [[nodiscard]] constexpr iterator begin( ) {
342 return first;
343 }
344 [[nodiscard]] constexpr iterator end( ) {
345 return last;
346 }
347 };
348
349 template<json_options_t PolicyFlags, typename Allocator>
354
358 template<json_options_t PolicyFlags, typename Allocator>
362 ParseState m_parse_state{ };
365 using size_type = std::size_t;
366 using difference_type = std::ptrdiff_t;
367
368 basic_json_value( ) = default;
369
372 template<json_options_t P, typename A>
373 explicit constexpr basic_json_value( BasicParsePolicy<P, A> parse_state )
374 : m_parse_state( std::move( parse_state ) ) {
375 // Ensure we are at the actual value.
376 if( DAW_LIKELY( not m_parse_state.empty( ) ) ) {
377 m_parse_state.trim_left( );
378 }
379 }
380
382 explicit constexpr basic_json_value( daw::string_view sv )
383 : m_parse_state( std::data( sv ), daw::data_end( sv ) ) {
384 if( DAW_LIKELY( not m_parse_state.empty( ) ) ) {
385 m_parse_state.trim_left( );
386 }
387 }
388
390 explicit constexpr basic_json_value( char const *first DAW_LIFETIME_BOUND,
391 std::size_t sz )
392 : m_parse_state(
393 first, first ? first + static_cast<std::ptrdiff_t>( sz ) : first ) {
394 if( DAW_LIKELY( not m_parse_state.empty( ) ) ) {
395 m_parse_state.trim_left( );
396 }
397 }
398
400 explicit constexpr basic_json_value( char const *first DAW_LIFETIME_BOUND,
401 char const *last )
402 : m_parse_state( first, last ) {
403 if( DAW_LIKELY( not m_parse_state.empty( ) ) ) {
404 m_parse_state.trim_left( );
405 }
406 }
407
410 [[nodiscard]] constexpr ParseState get_raw_state( ) const {
411 return m_parse_state;
412 }
413
414 [[nodiscard]] constexpr std::string_view get_raw_json_document( ) const {
415 return std::string_view( m_parse_state.first, m_parse_state.size( ) );
416 }
417
421 [[nodiscard]] constexpr iterator begin( ) const {
422 auto parse_state = ParseState( m_parse_state.first,
423 m_parse_state.last,
424 m_parse_state.first,
425 m_parse_state.last,
426 m_parse_state.get_allocator( ) );
427 if( DAW_LIKELY( not m_parse_state.empty( ) ) ) {
428 parse_state.remove_prefix( );
429 parse_state.trim_left( );
430 }
431 return iterator( parse_state );
432 }
433
436 [[nodiscard]] constexpr iterator end( ) const {
437 return iterator( );
438 }
439
444 [[nodiscard]] constexpr basic_json_value
445 find_class_member( daw::string_view name ) const {
446 if( type( ) != JsonBaseParseTypes::Class ) {
447 return basic_json_value{ };
448 }
449 bool const has_escape = name.contains( '\\' );
450 auto pos = [&] {
451 if( has_escape ) {
452 return daw::algorithm::find_if(
453 begin( ), end( ), [name]( auto const &jp ) {
454 assert( jp.name );
455 auto f0 = std::data( name );
456 auto const l0 = daw::data_end( name );
457 auto f1 = std::data( *jp.name );
458 auto const l1 = daw::data_end( *jp.name );
459 while( f0 != l0 and f1 != l1 ) {
460 if( *f0 == '\\' ) {
461 ++f0;
462 continue;
463 }
464 if( *f0 != *f1 ) {
465 return false;
466 }
467 ++f0;
468 ++f1;
469 }
470 return f0 == l0 and f1 == l1;
471 } );
472 } else {
473 return daw::algorithm::find_if(
474 begin( ), end( ), [name]( auto const &jp ) {
475 assert( jp.name );
476 return jp.name == name;
477 } );
478 }
479 }( );
480
481 if( pos == end( ) ) {
482 return basic_json_value( );
483 }
484 return ( *pos ).value;
485 }
486
489 [[nodiscard]] constexpr basic_json_value
490 find_member( daw::string_view json_path ) const {
491 auto jv = *this;
492 while( not json_path.empty( ) and jv ) {
493 auto member = [&] {
494 if( json_path.front( ) == '[' ) {
495 return json_path.pop_front_until( ']' );
496 }
497 return json_path.pop_front_until( escaped_any_of<'.', '['>{ },
498 nodiscard );
499 }( );
500 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
501 json_path.remove_prefix( );
502 }
503 if( member.front( ) == '[' ) {
504 member.remove_prefix( );
505 auto index_ps =
507 std::data( member ), daw::data_end( member ) )
508 .with_allocator( m_parse_state.get_allocator( ) );
509 auto const index =
510 json_details::unsigned_parser<std::size_t,
511 options::JsonRangeCheck::Never,
512 true>( index_ps );
513
514 jv = jv.find_element( index );
515 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
516 json_path.remove_prefix( );
517 }
518 continue;
519 }
520 jv = jv.find_class_member( member );
521 }
522 return jv;
523 }
524
527 template<typename Result>
528 [[nodiscard]] constexpr auto as( ) const {
529 using result_t = json_details::json_deduced_type<Result>;
530 auto state = m_parse_state;
531 return json_details::
532 parse_value<result_t, false, result_t::expected_type>( state );
533 }
534
535 template<typename Result>
536 [[nodiscard]] explicit operator Result( ) const {
537 return as<Result>( );
538 }
539
544 [[nodiscard]] constexpr basic_json_value
545 operator[]( daw::string_view json_path ) const {
546 return find_member( json_path );
547 }
548
552 [[nodiscard]] constexpr basic_json_value
553 find_element( std::size_t index ) const {
554 auto first = begin( );
555 auto const last = end( );
556 while( nsc_and( index > 0, first != last ) ) {
557 --index;
558 ++first;
559 }
560 if( index == 0 ) {
561 return ( *first ).value;
562 }
563 return basic_json_value( );
564 }
565
568 [[nodiscard]] constexpr basic_json_value
569 find_array_element( std::size_t index ) const {
570 assert( type( ) == JsonBaseParseTypes::Array );
571 return find_element( index );
572 }
573
577 [[nodiscard]] constexpr basic_json_value
578 operator[]( std::size_t index ) const {
579 return find_element( index );
580 }
581
585 [[nodiscard]] constexpr JsonBaseParseTypes type( ) const {
586 if( m_parse_state.empty( ) ) {
587 return JsonBaseParseTypes::None;
588 }
589 switch( m_parse_state.front( ) ) {
590 case '"':
591 return JsonBaseParseTypes::String;
592 case '{':
593 return JsonBaseParseTypes::Class;
594 case '[':
595 return JsonBaseParseTypes::Array;
596 case '-':
597 case '0':
598 case '1':
599 case '2':
600 case '3':
601 case '4':
602 case '5':
603 case '6':
604 case '7':
605 case '8':
606 case '9':
607 return JsonBaseParseTypes::Number;
608 case 't':
609 if constexpr( not ParseState::is_unchecked_input ) {
610 if( m_parse_state.starts_with( "true" ) ) {
611 return JsonBaseParseTypes::Bool;
612 }
613 return JsonBaseParseTypes::None;
614 } else {
615 return JsonBaseParseTypes::Bool;
616 }
617 case 'f':
618 if constexpr( not ParseState::is_unchecked_input ) {
619 if( m_parse_state.starts_with( "false" ) ) {
620 return JsonBaseParseTypes::Bool;
621 }
622 return JsonBaseParseTypes::None;
623 } else {
624 return JsonBaseParseTypes::Bool;
625 }
626 case 'n':
627 daw_json_assert_weak( m_parse_state.starts_with( "null" ),
628 ErrorReason::InvalidNull,
629 m_parse_state );
630 return JsonBaseParseTypes::Null;
631 }
632 return JsonBaseParseTypes::None;
633 }
634
637 [[nodiscard]] constexpr ParseState get_state( ) const {
638 auto parse_state = m_parse_state;
639 auto result = json_details::skip_value( parse_state );
640 if( is_string( ) ) {
641 --result.first;
642 ++result.last;
643 }
644 return result;
645 }
646
650 [[nodiscard]] constexpr std::string_view get_string_view( ) const {
651 auto parse_state = m_parse_state;
652 auto result = json_details::skip_value( parse_state );
653 return { std::data( result ), std::size( result ) };
654 }
655
659 template<typename Alloc = std::allocator<char>,
660 typename Traits = std::char_traits<char>>
661 [[nodiscard]] std::basic_string<char, Traits, Alloc>
662 get_string( Alloc const &alloc = Alloc( ) ) const {
663 auto parse_state = m_parse_state;
664 auto result = json_details::skip_value( parse_state );
665 return { std::data( result ), std::size( result ), alloc };
666 }
667
670 [[nodiscard]] constexpr bool is_null( ) const {
671 return type( ) == JsonBaseParseTypes::Null;
672 }
673
676 [[nodiscard]] constexpr bool is_class( ) const {
677 return type( ) == JsonBaseParseTypes::Class;
678 }
679
682 [[nodiscard]] constexpr bool is_array( ) const {
683 return type( ) == JsonBaseParseTypes::Array;
684 }
685
688 [[nodiscard]] constexpr bool is_number( ) const {
689 return type( ) == JsonBaseParseTypes::Number;
690 }
691
694 [[nodiscard]] constexpr bool is_string( ) const {
695 return type( ) == JsonBaseParseTypes::String;
696 }
697
700 [[nodiscard]] constexpr bool is_bool( ) const {
701 return type( ) == JsonBaseParseTypes::Bool;
702 }
703
708 [[nodiscard]] constexpr bool is_unknown( ) const {
709 return type( ) == JsonBaseParseTypes::None;
710 }
711
713 template<json_options_t P, typename A>
714 [[nodiscard]] constexpr
715 operator basic_json_value<P, A>( ) const noexcept {
716 auto new_range =
717 BasicParsePolicy<P, A>( m_parse_state.first, m_parse_state.last );
718 new_range.class_first = m_parse_state.class_first;
719 new_range.class_last = m_parse_state.class_last;
720 return basic_json_value<P, A>( std::move( new_range ) );
721 }
722
724 [[nodiscard]] explicit constexpr operator bool( ) const {
725 return type( ) != JsonBaseParseTypes::None;
726 }
727 };
728
729 template<json_options_t PolicyFlags, typename Allocator>
732
733 basic_json_value( daw::string_view ) -> basic_json_value<>;
734
735 basic_json_value( char const *first, std::size_t sz ) -> basic_json_value<>;
736
737 basic_json_value( char const *first, char const *last )
739
740 template<typename Result, json_options_t PolicyFlags, typename Allocator>
741 [[nodiscard]] constexpr Result
743 return jv.template as<Result>( );
744 }
745
746 namespace json_details {
747 // Will be specialized
748 template<typename>
749 inline constexpr bool is_json_value = false;
750
751 template<json_options_t PolicyFlags, typename Allocator>
752 inline constexpr bool
753 is_json_value<basic_json_value<PolicyFlags, Allocator>> = true;
754
755 template<json_options_t PolicyFlags, typename Allocator>
756 inline constexpr bool
757 is_string_view_like_v<basic_json_value<PolicyFlags, Allocator>> = false;
758 } // namespace json_details
759 } // namespace DAW_JSON_VER
760} // namespace daw::json
#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.
DAW_ATTRIB_NOINLINE void daw_json_error(bool b, ErrorReason reason)
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
constexpr Result as(basic_json_value< PolicyFlags, Allocator > const &jv)
constexpr decltype(auto) get(basic_json_pair< PolicyFlags, Allocator > const &parse_state)
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
Handles the bounds and policy items for parsing execution and comments.
TryDefaultParsePolicy< BasicParsePolicy< PolicyFlags, Allocator > > ParseState
a rudimentary range object for holding basic_json_value_iterator
Iterator for iterating over arbitrary JSON members and array elements.
constexpr pointer operator->()
Return an arrow_proxy object containing the result of operator* Should not use this method unless you...
constexpr std::optional< std::string_view > name() const
Name of member.
constexpr parse_policy const & get_raw_state() const
Get access to the internal state. Should not be used as part of public API.
TryDefaultParsePolicy< BasicParsePolicy< PolicyFlags, Allocator > > parse_policy
constexpr basic_json_value< PolicyFlags, Allocator > value() const
Get the value currently being referenced.
constexpr basic_json_value_iterator & operator++()
Move the parser to the next value.
constexpr bool is_class() const
Is the value this iterator iterates over an class.
constexpr bool is_array() const
Is the value this iterator iterates over an array.
constexpr bool operator==(basic_json_value_iterator< P, A > const &rhs) const
Check for equivalence with rhs iterator.
basic_json_value_iterator(daw::string_view json_doc, Allocator const &alloc)
basic_json_value_iterator(basic_json_value< PolicyFlags, Allocator > const &jv)
constexpr basic_json_pair< PolicyFlags, Allocator > operator*()
Get the name/value pair of the currently referenced element.
constexpr bool operator!=(basic_json_value_iterator< P, A > const &rhs) const
Check if rhs is not equivalent to self.
A non-owning container for arbitrary JSON values that allows movement/iteration through.
constexpr bool is_null() const
Is the JSON value a null literal.
constexpr bool is_class() const
Is the JSON value a class.
constexpr std::string_view get_string_view() const
Construct a string range of the current value. Strings start inside the quotes.
constexpr bool is_bool() const
Is the JSON value a boolean.
constexpr iterator end() const
End of range over class/arrays members/items.
constexpr basic_json_value operator[](daw::string_view json_path) const
Query the current class for a named member.
TryDefaultParsePolicy< BasicParsePolicy< PolicyFlags, Allocator > > ParseState
constexpr ParseState get_state() const
Construct a string range of the current value.
constexpr basic_json_value(daw::string_view sv)
Construct from string_view.
constexpr basic_json_value(char const *first DAW_LIFETIME_BOUND, std::size_t sz)
Construct from char const *, std::size_t.
constexpr auto as() const
Parse the current json member as a Result. The Result type must be supported or mapped via a json_dat...
constexpr basic_json_value find_array_element(std::size_t index) const
Find the nth element of the current json array.
constexpr iterator begin() const
Get the first member/item.
constexpr basic_json_value find_element(std::size_t index) const
Find the nth element/submember of the current json array or class.
constexpr basic_json_value find_member(daw::string_view json_path) const
find a class member/array element as specified by the json_path
constexpr bool is_array() const
Is the JSON value a array.
constexpr bool is_string() const
Is the JSON value a string.
constexpr bool is_number() const
Is the JSON value a number literal.
constexpr ParseState get_raw_state() const
Get a copy of the underlying parse state.
std::basic_string< char, Traits, Alloc > get_string(Alloc const &alloc=Alloc()) const
Construct a string range of the current value. Strings start inside the quotes.
constexpr basic_json_value(BasicParsePolicy< P, A > parse_state)
Construct from IteratorRange.
constexpr bool is_unknown() const
Is the JSON data unrecognizable. JSON members will start with one of ",[,{,0,1,2,3,...
constexpr basic_json_value(char const *first DAW_LIFETIME_BOUND, char const *last)
Construct from char const *, char const *.
constexpr JsonBaseParseTypes type() const
Get the type of JSON value.
constexpr basic_json_value operator[](std::size_t index) const
Find the nth element/submember of the current json array or class.
constexpr basic_json_value find_class_member(daw::string_view name) const
Query the current class for a named member.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20