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
23
24#include <daw/daw_algorithm.h>
25#include <daw/daw_move.h>
26#include <daw/daw_utility.h>
27
28#include <cassert>
29#include <cstddef>
30#include <daw/stdinc/tuple_traits.h>
31#include <optional>
32#include <string_view>
33
34namespace daw::json {
35 inline namespace DAW_JSON_VER {
38 template<json_options_t PolicyFlags = json_details::default_policy_flag,
39 typename Allocator = json_details::NoAllocator>
47
48 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
49 constexpr decltype( auto )
51 static_assert(
52 Idx < 2,
53 "Invalid index. Valid values are 0 for name, and 1 for value" );
54 if constexpr( Idx == 0 ) {
55 return parse_state.name;
56 } else {
57 return parse_state.value;
58 }
59 }
60
61 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
62 constexpr decltype( auto )
64 static_assert(
65 Idx < 2,
66 "Invalid index. Valid values are 0 for name, and 1 for value" );
67 if constexpr( Idx == 0 ) {
68 return parse_state.name;
69 } else {
70 return parse_state.value;
71 }
72 }
73
74 template<std::size_t Idx, json_options_t PolicyFlags, typename Allocator>
75 constexpr decltype( auto )
77 static_assert(
78 Idx < 2,
79 "Invalid index. Valid values are 0 for name, and 1 for value" );
80 if constexpr( Idx == 0 ) {
81 return std::move( parse_state.name );
82 } else {
83 return std::move( parse_state.value );
84 }
85 }
86 } // namespace DAW_JSON_VER
87} // namespace daw::json
88
89namespace std {
90 template<daw::json::json_options_t PolicyFlags, typename Allocator>
91 class tuple_element<0, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
92 public:
93 using type = std::optional<std::string_view>;
94 };
95
96 template<daw::json::json_options_t PolicyFlags, typename Allocator>
97 class tuple_element<1, daw::json::basic_json_pair<PolicyFlags, Allocator>> {
98 public:
100 };
101
102 template<daw::json::json_options_t PolicyFlags, typename Allocator>
103 inline constexpr std::size_t
104 tuple_size_v<daw::json::basic_json_pair<PolicyFlags, Allocator>> = 2;
105
106 template<daw::json::json_options_t PolicyFlags, typename Allocator>
107 class tuple_size<daw::json::basic_json_pair<PolicyFlags, Allocator>> {
108 static constexpr std::size_t value = 2;
109 };
110} // namespace std
111
112namespace daw::json {
113 inline namespace DAW_JSON_VER {
117 template<json_options_t PolicyFlags = json_details::default_policy_flag,
118 typename Allocator = json_details::NoAllocator>
120 using key_type = std::string_view;
122
126 using pointer = json_details::arrow_proxy<value_type>;
127 using difference_type = std::ptrdiff_t;
128 using iterator_category = std::forward_iterator_tag;
131
132 private:
134 ParseState m_state{ };
135
136 public:
137 explicit basic_json_value_iterator( ) = default;
138
139 explicit constexpr basic_json_value_iterator(
140 parse_policy const &parse_state )
141 : m_state( parse_state ) {}
142
143 explicit basic_json_value_iterator( daw::string_view json_doc )
144 : m_state( std::data( json_doc ), daw::data_end( json_doc ) ) {}
145
146 explicit basic_json_value_iterator( daw::string_view json_doc,
147 Allocator const &alloc )
148 : m_state( std::data( json_doc ), daw::data_end( json_doc ),
149 std::data( json_doc ), daw::data_end( json_doc ), alloc ) {}
150
153 : m_state( jv.get_raw_state( ) ) {}
154
157 [[nodiscard]] constexpr std::optional<std::string_view> name( ) const {
158 if( is_array( ) ) {
159 return { };
160 }
161 auto parse_state = m_state;
162 auto result = json_details::parse_name( parse_state );
163 return std::string_view( std::data( result ), std::size( result ) );
164 }
165
169 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
170 value( ) const {
171 if( is_array( ) ) {
172 return ParseState( m_state );
173 }
174 auto parse_state = m_state;
175 (void)json_details::parse_name( parse_state );
176 return ParseState( parse_state.first,
177 parse_state.last,
178 parse_state.first,
179 parse_state.last,
180 parse_state.get_allocator( ) );
181 }
182
185 [[nodiscard]] constexpr basic_json_pair<PolicyFlags, Allocator>
187 if( is_array( ) ) {
188 return { { },
189 basic_json_value( ParseState( m_state.first,
190 m_state.last,
191 m_state.first,
192 m_state.last,
193 m_state.get_allocator( ) ) ) };
194 }
195 auto parse_state = m_state;
196 auto name = json_details::parse_name( parse_state );
197 return {
198 std::string_view( std::data( name ), std::size( name ) ),
199 basic_json_value( ParseState( parse_state.first,
200 parse_state.last,
201 parse_state.first,
202 parse_state.last,
203 parse_state.get_allocator( ) ) ) };
204 }
205
210 [[nodiscard]] constexpr pointer operator->( ) {
211 return { operator*( ) };
212 }
213
217 if( good( ) ) {
218 if( is_class( ) ) {
219 (void)json_details::parse_name( m_state );
220 }
221 (void)json_details::skip_value( m_state );
222 m_state.move_next_member_or_end( );
223 }
224 return *this;
225 }
226
228 constexpr void operator++( int ) & {
229 operator++( );
230 }
231
234 [[nodiscard]] constexpr bool is_array( ) const {
235 return *m_state.class_first == '[';
236 }
237
240 [[nodiscard]] constexpr bool is_class( ) const {
241 return *m_state.class_first == '{';
242 }
243
246 [[nodiscard]] constexpr bool good( ) const {
247 if( m_state.is_null( ) or not m_state.has_more( ) ) {
248 return false;
249 }
250 switch( m_state.front( ) ) {
251 case '[':
252 case '{':
253 case '"':
254 case '-':
255 case '0':
256 case '1':
257 case '2':
258 case '3':
259 case '4':
260 case '5':
261 case '6':
262 case '7':
263 case '8':
264 case '9':
265 case 't':
266 case 'f':
267 case 'n':
268 return true;
269 case '}':
270 case ']':
271 return false;
272 default:
273 DAW_UNLIKELY_BRANCH
274 daw_json_error( ErrorReason::ExpectedTokenNotFound, m_state );
275 }
276 }
277
280 [[nodiscard]] constexpr explicit operator bool( ) const {
281 return good( );
282 }
283
286 [[nodiscard]] constexpr parse_policy const &get_raw_state( ) const {
287 return m_state;
288 }
289
293 template<json_options_t P, typename A>
294 [[nodiscard]] constexpr bool
296 if( good( ) ) {
297 if( rhs.good( ) ) {
298 return m_state.first == rhs.m_state.first;
299 }
300 return false;
301 }
302 return not rhs.good( );
303 }
304
308 template<json_options_t P, typename A>
309 [[nodiscard]] constexpr bool
311 return not operator==( rhs );
312 }
313 };
314
315 template<json_options_t PolicyFlags, typename Allocator>
319
320 basic_json_value_iterator( daw::string_view )
322
323 template<typename Allocator>
324 basic_json_value_iterator( daw::string_view, Allocator const & )
325 -> basic_json_value_iterator<daw::json::json_details::default_policy_flag,
326 Allocator>;
327
328 template<json_options_t PolicyFlags, typename Allocator>
332
335 template<json_options_t PolicyFlags = json_details::default_policy_flag,
336 typename Allocator = json_details::NoAllocator>
341
342 [[nodiscard]] constexpr iterator begin( ) {
343 return first;
344 }
345 [[nodiscard]] constexpr iterator end( ) {
346 return last;
347 }
348 };
349
350 template<json_options_t PolicyFlags, typename Allocator>
355
359 template<json_options_t PolicyFlags, typename Allocator>
363 ParseState m_parse_state{ };
366 using size_type = std::size_t;
367 using difference_type = std::ptrdiff_t;
368
369 basic_json_value( ) = default;
370
373 template<json_options_t P, typename A>
374 explicit constexpr basic_json_value( BasicParsePolicy<P, A> parse_state )
375 : m_parse_state( std::move( parse_state ) ) {
376 // Ensure we are at the actual value.
377 m_parse_state.trim_left( );
378 }
379
381 explicit constexpr basic_json_value( daw::string_view sv )
382 : m_parse_state( std::data( sv ), daw::data_end( sv ) ) {
383 m_parse_state.trim_left( );
384 }
385
387 explicit constexpr basic_json_value( char const *first, std::size_t sz )
388 : m_parse_state( first, first + static_cast<std::ptrdiff_t>( sz ) ) {
389 m_parse_state.trim_left( );
390 }
391
393 explicit constexpr basic_json_value( char const *first, char const *last )
394 : m_parse_state( first, last ) {
395 m_parse_state.trim_left( );
396 }
397
400 [[nodiscard]] constexpr ParseState get_raw_state( ) const {
401 return m_parse_state;
402 }
403
404 [[nodiscard]] constexpr std::string_view get_raw_json_document( ) const {
405 return std::string_view( m_parse_state.first, m_parse_state.size( ) );
406 }
407
411 [[nodiscard]] constexpr iterator begin( ) const {
412 auto parse_state = ParseState( m_parse_state.first,
413 m_parse_state.last,
414 m_parse_state.first,
415 m_parse_state.last,
416 m_parse_state.get_allocator( ) );
417 parse_state.remove_prefix( );
418 parse_state.trim_left( );
419 return iterator( parse_state );
420 }
421
424 [[nodiscard]] constexpr iterator end( ) const {
425 return iterator( );
426 }
427
432 [[nodiscard]] constexpr basic_json_value
433 find_class_member( daw::string_view name ) const {
434 if( type( ) != JsonBaseParseTypes::Class ) {
435 return basic_json_value{ };
436 }
437 bool const has_escape = name.contains( '\\' );
438 auto pos = [&] {
439 if( has_escape ) {
440 return daw::algorithm::find_if(
441 begin( ), end( ), [name]( auto const &jp ) {
442 assert( jp.name );
443 auto f0 = std::data( name );
444 auto const l0 = daw::data_end( name );
445 auto f1 = std::data( *jp.name );
446 auto const l1 = daw::data_end( *jp.name );
447 while( f0 != l0 and f1 != l1 ) {
448 if( *f0 == '\\' ) {
449 ++f0;
450 continue;
451 }
452 if( *f0 != *f1 ) {
453 return false;
454 }
455 ++f0;
456 ++f1;
457 }
458 return f0 == l0 and f1 == l1;
459 } );
460 } else {
461 return daw::algorithm::find_if(
462 begin( ), end( ), [name]( auto const &jp ) {
463 assert( jp.name );
464 return jp.name == name;
465 } );
466 }
467 }( );
468
469 if( pos == end( ) ) {
470 return basic_json_value( );
471 }
472 return ( *pos ).value;
473 }
474
477 [[nodiscard]] constexpr basic_json_value
478 find_member( daw::string_view json_path ) const {
479 auto jv = *this;
480 while( not json_path.empty( ) and jv ) {
481 auto member = [&] {
482 if( json_path.front( ) == '[' ) {
483 return json_path.pop_front_until( ']' );
484 }
485 return json_path.pop_front_until( escaped_any_of<'.', '['>{ },
486 nodiscard );
487 }( );
488 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
489 json_path.remove_prefix( );
490 }
491 if( member.front( ) == '[' ) {
492 member.remove_prefix( );
493 auto index_ps =
495 std::data( member ), daw::data_end( member ) )
496 .with_allocator( m_parse_state.get_allocator( ) );
497 auto const index =
498 json_details::unsigned_parser<std::size_t,
499 options::JsonRangeCheck::Never,
500 true>( index_ps );
501
502 jv = jv.find_element( index );
503 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
504 json_path.remove_prefix( );
505 }
506 continue;
507 }
508 jv = jv.find_class_member( member );
509 }
510 return jv;
511 }
512
515 template<typename Result>
516 [[nodiscard]] constexpr auto as( ) const {
517 using result_t = json_details::json_deduced_type<Result>;
518 auto state = m_parse_state;
519 return json_details::
520 parse_value<result_t, false, result_t::expected_type>( state );
521 }
522
523 template<typename Result>
524 [[nodiscard]] explicit operator Result( ) const {
525 return as<Result>( );
526 }
527
532 [[nodiscard]] constexpr basic_json_value
533 operator[]( daw::string_view json_path ) const {
534 return find_member( json_path );
535 }
536
540 [[nodiscard]] constexpr basic_json_value
541 find_element( std::size_t index ) const {
542 auto first = begin( );
543 auto const last = end( );
544 while( nsc_and( index > 0, first != last ) ) {
545 --index;
546 ++first;
547 }
548 if( index == 0 ) {
549 return ( *first ).value;
550 }
551 return basic_json_value( );
552 }
553
556 [[nodiscard]] constexpr basic_json_value
557 find_array_element( std::size_t index ) const {
558 assert( type( ) == JsonBaseParseTypes::Array );
559 return find_element( index );
560 }
561
565 [[nodiscard]] constexpr basic_json_value
566 operator[]( std::size_t index ) const {
567 return find_element( index );
568 }
569
573 [[nodiscard]] constexpr JsonBaseParseTypes type( ) const {
574 if( m_parse_state.empty( ) ) {
575 return JsonBaseParseTypes::None;
576 }
577 switch( m_parse_state.front( ) ) {
578 case '"':
579 return JsonBaseParseTypes::String;
580 case '{':
581 return JsonBaseParseTypes::Class;
582 case '[':
583 return JsonBaseParseTypes::Array;
584 case '-':
585 case '0':
586 case '1':
587 case '2':
588 case '3':
589 case '4':
590 case '5':
591 case '6':
592 case '7':
593 case '8':
594 case '9':
595 return JsonBaseParseTypes::Number;
596 case 't':
597 if constexpr( not ParseState::is_unchecked_input ) {
598 if( m_parse_state.starts_with( "true" ) ) {
599 return JsonBaseParseTypes::Bool;
600 }
601 return JsonBaseParseTypes::None;
602 } else {
603 return JsonBaseParseTypes::Bool;
604 }
605 case 'f':
606 if constexpr( not ParseState::is_unchecked_input ) {
607 if( m_parse_state.starts_with( "false" ) ) {
608 return JsonBaseParseTypes::Bool;
609 }
610 return JsonBaseParseTypes::None;
611 } else {
612 return JsonBaseParseTypes::Bool;
613 }
614 case 'n':
615 daw_json_assert_weak( m_parse_state.starts_with( "null" ),
616 ErrorReason::InvalidNull,
617 m_parse_state );
618 return JsonBaseParseTypes::Null;
619 }
620 return JsonBaseParseTypes::None;
621 }
622
625 [[nodiscard]] constexpr ParseState get_state( ) const {
626 auto parse_state = m_parse_state;
627 auto result = json_details::skip_value( parse_state );
628 if( is_string( ) ) {
629 --result.first;
630 ++result.last;
631 }
632 return result;
633 }
634
638 [[nodiscard]] constexpr std::string_view get_string_view( ) const {
639 auto parse_state = m_parse_state;
640 auto result = json_details::skip_value( parse_state );
641 return { std::data( result ), std::size( result ) };
642 }
643
647 template<typename Alloc = std::allocator<char>,
648 typename Traits = std::char_traits<char>>
649 [[nodiscard]] std::basic_string<char, Traits, Alloc>
650 get_string( Alloc const &alloc = Alloc( ) ) 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 ), alloc };
654 }
655
658 [[nodiscard]] constexpr bool is_null( ) const {
659 return type( ) == JsonBaseParseTypes::Null;
660 }
661
664 [[nodiscard]] constexpr bool is_class( ) const {
665 return type( ) == JsonBaseParseTypes::Class;
666 }
667
670 [[nodiscard]] constexpr bool is_array( ) const {
671 return type( ) == JsonBaseParseTypes::Array;
672 }
673
676 [[nodiscard]] constexpr bool is_number( ) const {
677 return type( ) == JsonBaseParseTypes::Number;
678 }
679
682 [[nodiscard]] constexpr bool is_string( ) const {
683 return type( ) == JsonBaseParseTypes::String;
684 }
685
688 [[nodiscard]] constexpr bool is_bool( ) const {
689 return type( ) == JsonBaseParseTypes::Bool;
690 }
691
696 [[nodiscard]] constexpr bool is_unknown( ) const {
697 return type( ) == JsonBaseParseTypes::None;
698 }
699
701 template<json_options_t P, typename A>
702 [[nodiscard]] constexpr
703 operator basic_json_value<P, A>( ) const noexcept {
704 auto new_range =
705 BasicParsePolicy<P, A>( m_parse_state.first, m_parse_state.last );
706 new_range.class_first = m_parse_state.class_first;
707 new_range.class_last = m_parse_state.class_last;
708 return basic_json_value<P, A>( std::move( new_range ) );
709 }
710
712 [[nodiscard]] explicit constexpr operator bool( ) const {
713 return type( ) != JsonBaseParseTypes::None;
714 }
715 };
716
717 template<json_options_t PolicyFlags, typename Allocator>
720
721 basic_json_value( daw::string_view ) -> basic_json_value<>;
722
723 basic_json_value( char const *first, std::size_t sz ) -> basic_json_value<>;
724
725 basic_json_value( char const *first, char const *last )
727
728 template<typename Result, json_options_t PolicyFlags, typename Allocator>
729 [[nodiscard]] constexpr Result
731 return jv.template as<Result>( );
732 }
733
734 namespace json_details {
735 // Will be specialized
736 template<typename>
737 inline constexpr bool is_json_value = false;
738
739 template<json_options_t PolicyFlags, typename Allocator>
740 inline constexpr bool
741 is_json_value<basic_json_value<PolicyFlags, Allocator>> = true;
742
743 template<json_options_t PolicyFlags, typename Allocator>
744 inline constexpr bool
745 is_string_view_like_v<basic_json_value<PolicyFlags, Allocator>> = false;
746 } // namespace json_details
747 } // namespace DAW_JSON_VER
748} // 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(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