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
11#include "version.h"
12
14#include "daw_json_assert.h"
15#include "daw_json_parse_name.h"
19#include "daw_json_skip.h"
20#include "daw_json_traits.h"
21#include "daw_json_value_fwd.h"
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 class tuple_size<daw::json::basic_json_pair<PolicyFlags, Allocator>>
104 : public std::integral_constant<std::size_t, 2> {};
105} // namespace std
106
107namespace daw::json {
108 inline namespace DAW_JSON_VER {
112 template<json_options_t PolicyFlags = json_details::default_policy_flag,
113 typename Allocator = json_details::NoAllocator>
115 using key_type = std::string_view;
117
121 using pointer = json_details::arrow_proxy<value_type>;
122 using difference_type = std::ptrdiff_t;
123 using iterator_category = std::forward_iterator_tag;
126
127 private:
129 ParseState m_state{ };
130
131 public:
132 explicit basic_json_value_iterator( ) = default;
133
134 explicit constexpr basic_json_value_iterator(
135 parse_policy const &parse_state )
136 : m_state( parse_state ) {}
137
138 explicit basic_json_value_iterator( daw::string_view json_doc )
139 : m_state( std::data( json_doc ), daw::data_end( json_doc ) ) {}
140
141 explicit basic_json_value_iterator( daw::string_view json_doc,
142 Allocator const &alloc )
143 : m_state( std::data( json_doc ), daw::data_end( json_doc ),
144 std::data( json_doc ), daw::data_end( json_doc ), alloc ) {}
145
148 : m_state( jv.get_raw_state( ) ) {}
149
152 [[nodiscard]] constexpr std::optional<std::string_view> name( ) const {
153 if( is_array( ) ) {
154 return { };
155 }
156 auto parse_state = m_state;
157 auto result = json_details::parse_name( parse_state );
158 return std::string_view( std::data( result ), std::size( result ) );
159 }
160
164 [[nodiscard]] constexpr basic_json_value<PolicyFlags, Allocator>
165 value( ) const {
166 if( is_array( ) ) {
167 return ParseState( m_state );
168 }
169 auto parse_state = m_state;
170 (void)json_details::parse_name( parse_state );
171 return ParseState( parse_state.first, parse_state.last,
172 parse_state.first, parse_state.last,
173 parse_state.get_allocator( ) );
174 }
175
178 [[nodiscard]] constexpr basic_json_pair<PolicyFlags, Allocator>
180 if( is_array( ) ) {
181 return { { },
182 basic_json_value( ParseState( m_state.first, m_state.last,
183 m_state.first, m_state.last,
184 m_state.get_allocator( ) ) ) };
185 }
186 auto parse_state = m_state;
187 auto name = json_details::parse_name( parse_state );
188 return { std::string_view( std::data( name ), std::size( name ) ),
190 parse_state.first, parse_state.last, parse_state.first,
191 parse_state.last, parse_state.get_allocator( ) ) ) };
192 }
193
198 [[nodiscard]] constexpr pointer operator->( ) {
199 return { operator*( ) };
200 }
201
205 if( good( ) ) {
206 if( is_class( ) ) {
207 (void)json_details::parse_name( m_state );
208 }
209 (void)json_details::skip_value( m_state );
210 m_state.move_next_member_or_end( );
211 }
212 return *this;
213 }
214
216 inline constexpr void operator++( int ) & {
217 operator++( );
218 }
219
222 [[nodiscard]] constexpr bool is_array( ) const {
223 return *m_state.class_first == '[';
224 }
225
228 [[nodiscard]] constexpr bool is_class( ) const {
229 return *m_state.class_first == '{';
230 }
231
234 [[nodiscard]] constexpr bool good( ) const {
235 if( not m_state.has_more( ) or m_state.is_null( ) ) {
236 return false;
237 }
238 switch( m_state.front( ) ) {
239 case '[':
240 case '{':
241 case '"':
242 case '-':
243 case '0':
244 case '1':
245 case '2':
246 case '3':
247 case '4':
248 case '5':
249 case '6':
250 case '7':
251 case '8':
252 case '9':
253 case 't':
254 case 'f':
255 case 'n':
256 return true;
257 case '}':
258 case ']':
259 return false;
260 default:
261 DAW_UNLIKELY_BRANCH
262 daw_json_error( ErrorReason::ExpectedTokenNotFound, m_state );
263 }
264 }
265
268 [[nodiscard]] constexpr explicit operator bool( ) const {
269 return good( );
270 }
271
274 [[nodiscard]] constexpr parse_policy const &get_raw_state( ) const {
275 return m_state;
276 }
277
281 template<json_options_t P, typename A>
282 [[nodiscard]] constexpr bool
284 if( good( ) ) {
285 if( rhs.good( ) ) {
286 return m_state.first == rhs.m_state.first;
287 }
288 return false;
289 }
290 return not rhs.good( );
291 }
292
296 template<json_options_t P, typename A>
297 [[nodiscard]] constexpr bool
299 return not operator==( rhs );
300 }
301 };
302
303 template<json_options_t PolicyFlags, typename Allocator>
307
308 basic_json_value_iterator( daw::string_view )
310
311 template<typename Allocator>
312 basic_json_value_iterator( daw::string_view, Allocator const & )
313 -> basic_json_value_iterator<daw::json::json_details::default_policy_flag,
314 Allocator>;
315
316 template<json_options_t PolicyFlags, typename Allocator>
320
323 template<json_options_t PolicyFlags = json_details::default_policy_flag,
324 typename Allocator = json_details::NoAllocator>
330
331 [[nodiscard]] constexpr iterator begin( ) {
332 return first;
333 }
334 [[nodiscard]] constexpr iterator end( ) {
335 return last;
336 }
337 };
338
339 template<json_options_t PolicyFlags, typename Allocator>
344
348 template<json_options_t PolicyFlags, typename Allocator>
352 ParseState m_parse_state{ };
353 using CharT = typename ParseState::CharT;
356 using size_type = std::size_t;
357 using difference_type = std::ptrdiff_t;
358
359 basic_json_value( ) = default;
360
363 template<json_options_t P, typename A>
364 explicit inline constexpr basic_json_value(
365 BasicParsePolicy<P, A> parse_state )
366 : m_parse_state( std::move( parse_state ) ) {
367 // Ensure we are at the actual value.
368 m_parse_state.trim_left( );
369 }
370
372 explicit inline constexpr basic_json_value( daw::string_view sv )
373 : m_parse_state( std::data( sv ), daw::data_end( sv ) ) {
374 m_parse_state.trim_left( );
375 }
376
378 explicit inline constexpr basic_json_value( CharT *first, std::size_t sz )
379 : m_parse_state( first, first + static_cast<std::ptrdiff_t>( sz ) ) {
380 m_parse_state.trim_left( );
381 }
382
384 explicit inline constexpr basic_json_value( CharT *first, CharT *last )
385 : m_parse_state( first, last ) {
386 m_parse_state.trim_left( );
387 }
388
391 [[nodiscard]] inline constexpr ParseState get_raw_state( ) const {
392 return m_parse_state;
393 }
394
395 [[nodiscard]] inline constexpr std::string_view
397 return std::string_view( m_parse_state.first, m_parse_state.size( ) );
398 }
399
403 [[nodiscard]] inline constexpr iterator begin( ) const {
404 auto parse_state = ParseState( m_parse_state.first, m_parse_state.last,
405 m_parse_state.first, m_parse_state.last,
406 m_parse_state.get_allocator( ) );
407 parse_state.remove_prefix( );
408 parse_state.trim_left( );
409 return iterator( parse_state );
410 }
411
414 [[nodiscard]] inline constexpr iterator end( ) const {
415 return iterator( );
416 }
417
422 [[nodiscard]] constexpr basic_json_value
423 find_class_member( daw::string_view name ) const {
424 if( type( ) != JsonBaseParseTypes::Class ) {
425 return basic_json_value{ };
426 }
427 bool const has_escape = name.contains( '\\' );
428 auto pos = [&] {
429 if( has_escape ) {
430 return daw::algorithm::find_if(
431 begin( ), end( ), [name]( auto const &jp ) {
432 assert( jp.name );
433 auto f0 = std::data( name );
434 auto const l0 = daw::data_end( name );
435 auto f1 = std::data( *jp.name );
436 auto const l1 = daw::data_end( *jp.name );
437 while( f0 != l0 and f1 != l1 ) {
438 if( *f0 == '\\' ) {
439 ++f0;
440 continue;
441 }
442 if( *f0 != *f1 ) {
443 return false;
444 }
445 ++f0;
446 ++f1;
447 }
448 return f0 == l0 and f1 == l1;
449 } );
450 } else {
451 return daw::algorithm::find_if( begin( ), end( ),
452 [name]( auto const &jp ) {
453 assert( jp.name );
454 return jp.name == name;
455 } );
456 }
457 }( );
458
459 if( pos == end( ) ) {
460 return basic_json_value( );
461 }
462 return ( *pos ).value;
463 }
464
467 [[nodiscard]] constexpr basic_json_value
468 find_member( daw::string_view json_path ) const {
469 auto jv = *this;
470 while( not json_path.empty( ) and jv ) {
471 auto member = [&] {
472 if( json_path.front( ) == '[' ) {
473 return json_path.pop_front_until( ']' );
474 }
475 return json_path.pop_front_until( escaped_any_of<'.', '['>{ },
476 nodiscard );
477 }( );
478 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
479 json_path.remove_prefix( );
480 }
481 if( member.front( ) == '[' ) {
482 member.remove_prefix( );
483 auto index_ps =
485 std::data( member ), daw::data_end( member ) )
486 .with_allocator( m_parse_state.get_allocator( ) );
487 auto const index = json_details::unsigned_parser<
488 std::size_t, options::JsonRangeCheck::Never, true>(
489 constexpr_exec_tag{ }, index_ps );
490
491 jv = jv.find_element( index );
492 if( not json_path.empty( ) and json_path.front( ) == '.' ) {
493 json_path.remove_prefix( );
494 }
495 continue;
496 }
497 jv = jv.find_class_member( member );
498 }
499 return jv;
500 }
501
504 template<typename Result>
505 [[nodiscard]] constexpr auto as( ) const {
506 using result_t = json_details::json_deduced_type<Result>;
507 auto state = m_parse_state;
508 return json_details::parse_value<result_t, false,
509 result_t::expected_type>( state );
510 }
511
512 template<typename Result>
513 [[nodiscard]] explicit operator Result( ) const {
514 return as<Result>( );
515 }
516
521 [[nodiscard]] constexpr basic_json_value
522 operator[]( daw::string_view json_path ) const {
523 return find_member( json_path );
524 }
525
529 [[nodiscard]] constexpr basic_json_value
530 find_element( std::size_t index ) const {
531 auto first = begin( );
532 auto const last = end( );
533 while( nsc_and( index > 0, first != last ) ) {
534 --index;
535 ++first;
536 }
537 if( index == 0 ) {
538 return ( *first ).value;
539 }
540 return basic_json_value( );
541 }
542
545 [[nodiscard]] constexpr basic_json_value
546 find_array_element( std::size_t index ) const {
547 assert( type( ) == JsonBaseParseTypes::Array );
548 return find_element( index );
549 }
550
554 [[nodiscard]] constexpr basic_json_value
555 operator[]( std::size_t index ) const {
556 return find_element( index );
557 }
558
562 [[nodiscard]] constexpr JsonBaseParseTypes type( ) const {
563 if( not m_parse_state.has_more( ) ) {
564 return JsonBaseParseTypes::None;
565 }
566 switch( m_parse_state.front( ) ) {
567 case '"':
568 return JsonBaseParseTypes::String;
569 case '{':
570 return JsonBaseParseTypes::Class;
571 case '[':
572 return JsonBaseParseTypes::Array;
573 case '-':
574 case '0':
575 case '1':
576 case '2':
577 case '3':
578 case '4':
579 case '5':
580 case '6':
581 case '7':
582 case '8':
583 case '9':
584 return JsonBaseParseTypes::Number;
585 case 't':
586 if constexpr( not ParseState::is_unchecked_input ) {
587 if( m_parse_state.starts_with( "true" ) ) {
588 return JsonBaseParseTypes::Bool;
589 }
590 return JsonBaseParseTypes::None;
591 } else {
592 return JsonBaseParseTypes::Bool;
593 }
594 case 'f':
595 if constexpr( not ParseState::is_unchecked_input ) {
596 if( m_parse_state.starts_with( "false" ) ) {
597 return JsonBaseParseTypes::Bool;
598 }
599 return JsonBaseParseTypes::None;
600 } else {
601 return JsonBaseParseTypes::Bool;
602 }
603 case 'n':
604 daw_json_assert_weak( m_parse_state.starts_with( "null" ),
605 ErrorReason::InvalidNull, m_parse_state );
606 return JsonBaseParseTypes::Null;
607 }
608 return JsonBaseParseTypes::None;
609 }
610
613 [[nodiscard]] constexpr ParseState get_state( ) const {
614 auto parse_state = m_parse_state;
615 auto result = json_details::skip_value( parse_state );
616 if( is_string( ) ) {
617 --result.first;
618 ++result.last;
619 }
620 return result;
621 }
622
626 [[nodiscard]] constexpr std::string_view get_string_view( ) const {
627 auto parse_state = m_parse_state;
628 auto result = json_details::skip_value( parse_state );
629 return { std::data( result ), std::size( result ) };
630 }
631
635 template<typename Alloc = std::allocator<char>,
636 typename Traits = std::char_traits<char>>
637 [[nodiscard]] std::basic_string<char, Traits, Alloc>
638 get_string( Alloc const &alloc = Alloc( ) ) 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 ), alloc };
642 }
643
646 [[nodiscard]] constexpr bool is_null( ) const {
647 return type( ) == JsonBaseParseTypes::Null;
648 }
649
652 [[nodiscard]] constexpr bool is_class( ) const {
653 return type( ) == JsonBaseParseTypes::Class;
654 }
655
658 [[nodiscard]] constexpr bool is_array( ) const {
659 return type( ) == JsonBaseParseTypes::Array;
660 }
661
664 [[nodiscard]] constexpr bool is_number( ) const {
665 return type( ) == JsonBaseParseTypes::Number;
666 }
667
670 [[nodiscard]] inline constexpr bool is_string( ) const {
671 return type( ) == JsonBaseParseTypes::String;
672 }
673
676 [[nodiscard]] constexpr bool is_bool( ) const {
677 return type( ) == JsonBaseParseTypes::Bool;
678 }
679
684 [[nodiscard]] inline constexpr bool is_unknown( ) const {
685 return type( ) == JsonBaseParseTypes::None;
686 }
687
689 template<json_options_t P, typename A>
690 [[nodiscard]] constexpr
691 operator basic_json_value<P, A>( ) const noexcept {
692 auto new_range =
693 BasicParsePolicy<P, A>( m_parse_state.first, m_parse_state.last );
694 new_range.class_first = m_parse_state.class_first;
695 new_range.class_last = m_parse_state.class_last;
696 return basic_json_value<P, A>( std::move( new_range ) );
697 }
698
700 [[nodiscard]] explicit constexpr operator bool( ) const {
701 return type( ) != JsonBaseParseTypes::None;
702 }
703 };
704
705 template<json_options_t PolicyFlags, typename Allocator>
708
709 basic_json_value( daw::string_view ) -> basic_json_value<>;
710
711 basic_json_value( char const *first, std::size_t sz ) -> basic_json_value<>;
712
713 basic_json_value( char const *first,
714 char const *last ) -> basic_json_value<>;
715
716 template<typename Result, json_options_t PolicyFlags, typename Allocator>
717 [[nodiscard]] constexpr Result
719 return jv.template as<Result>( );
720 }
721
722 namespace json_details {
723 template<typename>
724 inline constexpr bool is_json_value = false;
725
726 template<json_options_t PolicyFlags, typename Allocator>
727 inline constexpr bool
728 is_json_value<basic_json_value<PolicyFlags, Allocator>> = true;
729
730 template<json_options_t PolicyFlags, typename Allocator>
731 inline constexpr bool
732 is_string_view_like_v<basic_json_value<PolicyFlags, Allocator>> = false;
733 } // namespace json_details
734 } // namespace DAW_JSON_VER
735} // 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
typename BasicParsePolicy< PolicyFlags, Allocator >::CharT CharT
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(CharT *first, CharT *last)
Construct from CharT *, CharT *.
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.
constexpr basic_json_value(CharT *first, std::size_t sz)
Construct from CharT *, std::size_t.
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