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_move.h>
27#include <daw/daw_utility.h>
28
29#include <cassert>
30#include <cstddef>
31#include <daw/stdinc/tuple_traits.h>
32#include <optional>
33#include <string_view>
34
35namespace daw::json {
36 inline namespace DAW_JSON_VER {
39 template<json_options_t PolicyFlags = json_details::default_policy_flag,
40 typename Allocator = json_details::NoAllocator>
48
49 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
50 constexpr decltype( auto )
52 static_assert(
53 Idx < 2,
54 "Invalid index. Valid values are 0 for name, and 1 for value" );
55 if constexpr( Idx == 0 ) {
56 return parse_state.name;
57 } else {
58 return parse_state.value;
59 }
60 }
61
62 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
63 constexpr decltype( auto )
65 static_assert(
66 Idx < 2,
67 "Invalid index. Valid values are 0 for name, and 1 for value" );
68 if constexpr( Idx == 0 ) {
69 return parse_state.name;
70 } else {
71 return parse_state.value;
72 }
73 }
74
75 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
76 constexpr decltype( auto )
78 static_assert(
79 Idx < 2,
80 "Invalid index. Valid values are 0 for name, and 1 for value" );
81 if constexpr( Idx == 0 ) {
82 return std::move( parse_state.name );
83 } else {
84 return std::move( parse_state.value );
85 }
86 }
87 } // namespace DAW_JSON_VER
88} // namespace daw::json
89
90namespace std {
91 template<daw::json::json_options_t PolicyFlags, typename Allocator>
92 class tuple_element<0, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
93 public:
94 using type = std::optional<std::string_view>;
95 };
96
97 template<daw::json::json_options_t PolicyFlags, typename Allocator>
98 class tuple_element<1, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
99 public:
101 };
102
103 template<daw::json::json_options_t PolicyFlags, typename Allocator>
104 inline constexpr std::size_t
105 tuple_size_v<daw::json::basic_json_pair<PolicyFlags, Allocator>> = 2;
106
107 template<daw::json::json_options_t PolicyFlags, typename Allocator>
108 class tuple_size<daw::json::basic_json_pair<PolicyFlags, Allocator>> {
109 public:
110 static constexpr std::size_t value = 2;
111 };
112} // namespace std
113
114namespace daw::json {
115 inline namespace DAW_JSON_VER {
119 template<json_options_t PolicyFlags = json_details::default_policy_flag,
120 typename Allocator = json_details::NoAllocator>
122 using key_type = std::string_view;
124
128 using pointer = json_details::arrow_proxy<value_type>;
129 using difference_type = std::ptrdiff_t;
130 using iterator_category = std::forward_iterator_tag;
133
134 private:
136 ParseState m_state{ };
137
138 public:
139 explicit basic_json_value_iterator( ) = default;
140
141 explicit constexpr basic_json_value_iterator(
142 parse_policy const &parse_state )
143 : m_state( parse_state ) {}
144
145 explicit basic_json_value_iterator( daw::string_view json_doc )
146 : m_state( std::data( json_doc ), daw::data_end( json_doc ) ) {}
147
148 explicit basic_json_value_iterator( daw::string_view json_doc,
149 Allocator const &alloc )
150 : m_state( std::data( json_doc ), daw::data_end( json_doc ),
151 std::data( json_doc ), daw::data_end( json_doc ), alloc ) {}
152
155 : m_state( jv.get_raw_state( ) ) {}
156
159 [[nodiscard]] constexpr std::optional<std::string_view> name( ) const {
160 if( is_array( ) ) {
161 return { };
162 }
163 auto parse_state = m_state;
164 auto result = json_details::parse_name( parse_state );
165 return std::string_view( std::data( result ), std::size( result ) );
166 }
167
171 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
172 value( ) const {
173 if( is_array( ) ) {
174 return ParseState( m_state );
175 }
176 auto parse_state = m_state;
177 (void)json_details::parse_name( parse_state );
178 return ParseState( parse_state.first,
179 parse_state.last,
180 parse_state.first,
181 parse_state.last,
182 parse_state.get_allocator( ) );
183 }
184
187 [[nodiscard]] constexpr basic_json_pair<PolicyFlags, Allocator>
189 if( is_array( ) ) {
190 return { { },
191 basic_json_value( ParseState( m_state.first,
192 m_state.last,
193 m_state.first,
194 m_state.last,
195 m_state.get_allocator( ) ) ) };
196 }
197 auto parse_state = m_state;
198 auto name = json_details::parse_name( parse_state );
199 return {
200 std::string_view( std::data( name ), std::size( name ) ),
201 basic_json_value( ParseState( parse_state.first,
202 parse_state.last,
203 parse_state.first,
204 parse_state.last,
205 parse_state.get_allocator( ) ) ) };
206 }
207
212 [[nodiscard]] constexpr pointer operator->( ) {
213 return { operator*( ) };
214 }
215
219 if( good( ) ) {
220 if( is_class( ) ) {
221 (void)json_details::parse_name( m_state );
222 }
223 (void)json_details::skip_value( m_state );
224 m_state.move_next_member_or_end( );
225 }
226 return *this;
227 }
228
230 constexpr void operator++( int ) & {
231 operator++( );
232 }
233
236 [[nodiscard]] constexpr bool is_array( ) const {
237 return *m_state.class_first == '[';
238 }
239
242 [[nodiscard]] constexpr bool is_class( ) const {
243 return *m_state.class_first == '{';
244 }
245
248 [[nodiscard]] constexpr bool good( ) const {
249 if( m_state.is_null( ) or not m_state.has_more( ) ) {
250 return false;
251 }
252 switch( m_state.front( ) ) {
253 case '[':
254 case '{':
255 case '"':
256 case '-':
257 case '0':
258 case '1':
259 case '2':
260 case '3':
261 case '4':
262 case '5':
263 case '6':
264 case '7':
265 case '8':
266 case '9':
267 case 't':
268 case 'f':
269 case 'n':
270 return true;
271 case '}':
272 case ']':
273 return false;
274 default:
275 DAW_UNLIKELY_BRANCH
276 daw_json_error( true, ErrorReason::ExpectedTokenNotFound, m_state );
277 }
278 }
279
282 [[nodiscard]] constexpr explicit operator bool( ) const {
283 return good( );
284 }
285
288 [[nodiscard]] constexpr parse_policy const &get_raw_state( ) const {
289 return m_state;
290 }
291
295 template<json_options_t P, typename A>
296 [[nodiscard]] constexpr bool
298 if( good( ) ) {
299 if( rhs.good( ) ) {
300 return m_state.first == rhs.m_state.first;
301 }
302 return false;
303 }
304 return not rhs.good( );
305 }
306
310 template<json_options_t P, typename A>
311 [[nodiscard]] constexpr bool
313 return not operator==( rhs );
314 }
315 };
316
317 template<json_options_t PolicyFlags, typename Allocator>
321
322 basic_json_value_iterator( daw::string_view )
324
325 template<typename Allocator>
326 basic_json_value_iterator( daw::string_view, Allocator const & )
327 -> basic_json_value_iterator<daw::json::json_details::default_policy_flag,
328 Allocator>;
329
330 template<json_options_t PolicyFlags, typename Allocator>
334
337 template<json_options_t PolicyFlags = json_details::default_policy_flag,
338 typename Allocator = json_details::NoAllocator>
343
344 [[nodiscard]] constexpr iterator begin( ) {
345 return first;
346 }
347 [[nodiscard]] constexpr iterator end( ) {
348 return last;
349 }
350 };
351
352 template<json_options_t PolicyFlags, typename Allocator>
357
361 template<json_options_t PolicyFlags, typename Allocator>
365 ParseState m_parse_state{ };
368 using size_type = std::size_t;
369 using difference_type = std::ptrdiff_t;
370
371 basic_json_value( ) = default;
372
375 template<json_options_t P, typename A>
376 explicit constexpr basic_json_value( BasicParsePolicy<P, A> parse_state )
377 : m_parse_state( std::move( parse_state ) ) {
378 // Ensure we are at the actual value.
379 m_parse_state.trim_left( );
380 }
381
383 explicit constexpr basic_json_value( daw::string_view sv )
384 : m_parse_state( std::data( sv ), daw::data_end( sv ) ) {
385 m_parse_state.trim_left( );
386 }
387
389 explicit constexpr basic_json_value( char const *first, std::size_t sz )
390 : m_parse_state( first, first + static_cast<std::ptrdiff_t>( sz ) ) {
391 m_parse_state.trim_left( );
392 }
393
395 explicit constexpr basic_json_value( char const *first, char const *last )
396 : m_parse_state( first, last ) {
397 m_parse_state.trim_left( );
398 }
399
402 [[nodiscard]] constexpr ParseState get_raw_state( ) const {
403 return m_parse_state;
404 }
405
406 [[nodiscard]] constexpr std::string_view get_raw_json_document( ) const {
407 return std::string_view( m_parse_state.first, m_parse_state.size( ) );
408 }
409
413 [[nodiscard]] constexpr iterator begin( ) const {
414 auto parse_state = ParseState( m_parse_state.first,
415 m_parse_state.last,
416 m_parse_state.first,
417 m_parse_state.last,
418 m_parse_state.get_allocator( ) );
419 parse_state.remove_prefix( );
420 parse_state.trim_left( );
421 return iterator( parse_state );
422 }
423
426 [[nodiscard]] constexpr iterator end( ) const {
427 return iterator( );
428 }
429
434 [[nodiscard]] constexpr basic_json_value
435 find_class_member( daw::string_view name ) const {
436 if( type( ) != JsonBaseParseTypes::Class ) {
437 return basic_json_value{ };
438 }
439 bool const has_escape = name.contains( '\\' );
440 auto pos = [&] {
441 if( has_escape ) {
442 return daw::algorithm::find_if(
443 begin( ), end( ), [name]( auto const &jp ) {
444 assert( jp.name );
445 auto f0 = std::data( name );
446 auto const l0 = daw::data_end( name );
447 auto f1 = std::data( *jp.name );
448 auto const l1 = daw::data_end( *jp.name );
449 while( f0 != l0 and f1 != l1 ) {
450 if( *f0 == '\\' ) {
451 ++f0;
452 continue;
453 }
454 if( *f0 != *f1 ) {
455 return false;
456 }
457 ++f0;
458 ++f1;
459 }
460 return f0 == l0 and f1 == l1;
461 } );
462 } else {
463 return daw::algorithm::find_if(
464 begin( ), end( ), [name]( auto const &jp ) {
465 assert( jp.name );
466 return jp.name == name;
467 } );
468 }
469 }( );
470
471 if( pos == end( ) ) {
472 return basic_json_value( );
473 }
474 return ( *pos ).value;
475 }
476
479 [[nodiscard]] constexpr basic_json_value
480 find_member( daw::string_view json_path ) const {
481 auto jv = *this;
482 while( not json_path.empty( ) and jv ) {
483 auto member = [&] {
484 if( json_path.front( ) == '[' ) {
485 return json_path.pop_front_until( ']' );
486 }
487 return json_path.pop_front_until( escaped_any_of<'.', '['>{ },
488 nodiscard );
489 }( );
490 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
491 json_path.remove_prefix( );
492 }
493 if( member.front( ) == '[' ) {
494 member.remove_prefix( );
495 auto index_ps =
497 std::data( member ), daw::data_end( member ) )
498 .with_allocator( m_parse_state.get_allocator( ) );
499 auto const index =
500 json_details::unsigned_parser<std::size_t,
501 options::JsonRangeCheck::Never,
502 true>( index_ps );
503
504 jv = jv.find_element( index );
505 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
506 json_path.remove_prefix( );
507 }
508 continue;
509 }
510 jv = jv.find_class_member( member );
511 }
512 return jv;
513 }
514
517 template<typename Result>
518 [[nodiscard]] constexpr auto as( ) const {
519 using result_t = json_details::json_deduced_type<Result>;
520 auto state = m_parse_state;
521 return json_details::
522 parse_value<result_t, false, result_t::expected_type>( state );
523 }
524
525 template<typename Result>
526 [[nodiscard]] explicit operator Result( ) const {
527 return as<Result>( );
528 }
529
534 [[nodiscard]] constexpr basic_json_value
535 operator[]( daw::string_view json_path ) const {
536 return find_member( json_path );
537 }
538
542 [[nodiscard]] constexpr basic_json_value
543 find_element( std::size_t index ) const {
544 auto first = begin( );
545 auto const last = end( );
546 while( nsc_and( index > 0, first != last ) ) {
547 --index;
548 ++first;
549 }
550 if( index == 0 ) {
551 return ( *first ).value;
552 }
553 return basic_json_value( );
554 }
555
558 [[nodiscard]] constexpr basic_json_value
559 find_array_element( std::size_t index ) const {
560 assert( type( ) == JsonBaseParseTypes::Array );
561 return find_element( index );
562 }
563
567 [[nodiscard]] constexpr basic_json_value
568 operator[]( std::size_t index ) const {
569 return find_element( index );
570 }
571
575 [[nodiscard]] constexpr JsonBaseParseTypes type( ) const {
576 if( m_parse_state.empty( ) ) {
577 return JsonBaseParseTypes::None;
578 }
579 switch( m_parse_state.front( ) ) {
580 case '"':
581 return JsonBaseParseTypes::String;
582 case '{':
583 return JsonBaseParseTypes::Class;
584 case '[':
585 return JsonBaseParseTypes::Array;
586 case '-':
587 case '0':
588 case '1':
589 case '2':
590 case '3':
591 case '4':
592 case '5':
593 case '6':
594 case '7':
595 case '8':
596 case '9':
597 return JsonBaseParseTypes::Number;
598 case 't':
599 if constexpr( not ParseState::is_unchecked_input ) {
600 if( m_parse_state.starts_with( "true" ) ) {
601 return JsonBaseParseTypes::Bool;
602 }
603 return JsonBaseParseTypes::None;
604 } else {
605 return JsonBaseParseTypes::Bool;
606 }
607 case 'f':
608 if constexpr( not ParseState::is_unchecked_input ) {
609 if( m_parse_state.starts_with( "false" ) ) {
610 return JsonBaseParseTypes::Bool;
611 }
612 return JsonBaseParseTypes::None;
613 } else {
614 return JsonBaseParseTypes::Bool;
615 }
616 case 'n':
617 daw_json_assert_weak( m_parse_state.starts_with( "null" ),
618 ErrorReason::InvalidNull,
619 m_parse_state );
620 return JsonBaseParseTypes::Null;
621 }
622 return JsonBaseParseTypes::None;
623 }
624
627 [[nodiscard]] constexpr ParseState get_state( ) const {
628 auto parse_state = m_parse_state;
629 auto result = json_details::skip_value( parse_state );
630 if( is_string( ) ) {
631 --result.first;
632 ++result.last;
633 }
634 return result;
635 }
636
640 [[nodiscard]] constexpr std::string_view get_string_view( ) const {
641 auto parse_state = m_parse_state;
642 auto result = json_details::skip_value( parse_state );
643 return { std::data( result ), std::size( result ) };
644 }
645
649 template<typename Alloc = std::allocator<char>,
650 typename Traits = std::char_traits<char>>
651 [[nodiscard]] std::basic_string<char, Traits, Alloc>
652 get_string( Alloc const &alloc = Alloc( ) ) const {
653 auto parse_state = m_parse_state;
654 auto result = json_details::skip_value( parse_state );
655 return { std::data( result ), std::size( result ), alloc };
656 }
657
660 [[nodiscard]] constexpr bool is_null( ) const {
661 return type( ) == JsonBaseParseTypes::Null;
662 }
663
666 [[nodiscard]] constexpr bool is_class( ) const {
667 return type( ) == JsonBaseParseTypes::Class;
668 }
669
672 [[nodiscard]] constexpr bool is_array( ) const {
673 return type( ) == JsonBaseParseTypes::Array;
674 }
675
678 [[nodiscard]] constexpr bool is_number( ) const {
679 return type( ) == JsonBaseParseTypes::Number;
680 }
681
684 [[nodiscard]] constexpr bool is_string( ) const {
685 return type( ) == JsonBaseParseTypes::String;
686 }
687
690 [[nodiscard]] constexpr bool is_bool( ) const {
691 return type( ) == JsonBaseParseTypes::Bool;
692 }
693
698 [[nodiscard]] constexpr bool is_unknown( ) const {
699 return type( ) == JsonBaseParseTypes::None;
700 }
701
703 template<json_options_t P, typename A>
704 [[nodiscard]] constexpr
705 operator basic_json_value<P, A>( ) const noexcept {
706 auto new_range =
707 BasicParsePolicy<P, A>( m_parse_state.first, m_parse_state.last );
708 new_range.class_first = m_parse_state.class_first;
709 new_range.class_last = m_parse_state.class_last;
710 return basic_json_value<P, A>( std::move( new_range ) );
711 }
712
714 [[nodiscard]] explicit constexpr operator bool( ) const {
715 return type( ) != JsonBaseParseTypes::None;
716 }
717 };
718
719 template<json_options_t PolicyFlags, typename Allocator>
722
723 basic_json_value( daw::string_view ) -> basic_json_value<>;
724
725 basic_json_value( char const *first, std::size_t sz ) -> basic_json_value<>;
726
727 basic_json_value( char const *first, char const *last )
729
730 template<typename Result, json_options_t PolicyFlags, typename Allocator>
731 [[nodiscard]] constexpr Result
733 return jv.template as<Result>( );
734 }
735
736 namespace json_details {
737 // Will be specialized
738 template<typename>
739 inline constexpr bool is_json_value = false;
740
741 template<json_options_t PolicyFlags, typename Allocator>
742 inline constexpr bool
743 is_json_value<basic_json_value<PolicyFlags, Allocator>> = true;
744
745 template<json_options_t PolicyFlags, typename Allocator>
746 inline constexpr bool
747 is_string_view_like_v<basic_json_value<PolicyFlags, Allocator>> = false;
748 } // namespace json_details
749 } // namespace DAW_JSON_VER
750} // 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)
Customization point traits.
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(char const *first, std::size_t sz)
Construct from char const *, std::size_t.
constexpr basic_json_value(char const *first, char const *last)
Construct from char const *, char const *.
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 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 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