DAW JSON Link
Loading...
Searching...
No Matches
daw_json_parse_policy.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/cpp_17.h>
25#include <daw/daw_attributes.h>
26#include <daw/daw_consteval.h>
27#include <daw/daw_likely.h>
28#include <daw/daw_not_null.h>
29#include <daw/daw_rw_ref.h>
30#include <daw/daw_traits.h>
31
32#include <cassert>
33#include <cstddef>
34#include <iterator>
35#include <type_traits>
36
37namespace daw::json {
38 inline namespace DAW_JSON_VER {
49 template<json_options_t PolicyFlags = json_details::default_policy_flag,
50 typename Allocator = json_details::NoAllocator>
51 struct BasicParsePolicy : json_details::AllocatorWrapper<Allocator> {
52
53 using i_am_a_parse_policy = void;
54 static constexpr bool is_default_parse_policy =
55 PolicyFlags == json_details::default_policy_flag and
56 std::is_same_v<Allocator, json_details::NoAllocator>;
57
58 static DAW_CONSTEVAL json_options_t policy_flags( ) {
59 return PolicyFlags;
60 }
61
62 /***
63 * see options::CheckedParseMode
64 */
65 static constexpr bool is_unchecked_input =
66 json_details::get_bits_for<options::CheckedParseMode>( PolicyFlags ) ==
67 options::CheckedParseMode::no;
68
69 /***
70 * See options::ExecModeTypes
71 */
72 using exec_tag_t = switch_t<
73 json_details::get_bits_for<options::ExecModeTypes, std::size_t>(
74 PolicyFlags ),
76
77 static constexpr auto exec_tag = exec_tag_t{ };
78
79 /***
80 * see options::AllowEscapedNames
81 */
82 static constexpr bool allow_escaped_names =
83 json_details::get_bits_for<options::AllowEscapedNames>( PolicyFlags ) ==
84 options::AllowEscapedNames::yes;
85
86 /***
87 * see options::ForceFullNameCheck
88 */
89 static constexpr bool force_name_equal_check =
90 json_details::get_bits_for<options::ForceFullNameCheck>(
91 PolicyFlags ) == options::ForceFullNameCheck::yes;
92
93 /***
94 * see options::ZeroTerminatedString
95 */
96 static constexpr bool is_zero_terminated_string =
97 json_details::get_bits_for<options::ZeroTerminatedString>(
98 PolicyFlags ) == options::ZeroTerminatedString::yes;
99
100 /***
101 * see options::AllowStringMutation
102 */
103 static constexpr bool allow_string_mutation =
104 json_details::get_bits_for<options::AllowStringMutation>(
105 PolicyFlags ) == options::AllowStringMutation::yes;
106
107 /***
108 * See options::IEEE754Precise
109 */
110 static constexpr bool precise_ieee754 =
111 json_details::get_bits_for<options::IEEE754Precise>( PolicyFlags ) ==
112 options::IEEE754Precise::yes;
113
114 /***
115 * See options::MinifiedDocument
116 */
117 static constexpr bool minified_document =
118 json_details::get_bits_for<options::MinifiedDocument>( PolicyFlags ) ==
119 options::MinifiedDocument::yes;
120
121 /***
122 * See options::ExcludeSpecialEscapes
123 */
124 static constexpr bool exclude_special_escapes =
125 json_details::get_bits_for<options::ExcludeSpecialEscapes>(
126 PolicyFlags ) == options::ExcludeSpecialEscapes::yes;
127
129 static constexpr bool allow_leading_zero_plus = true;
130
131 static constexpr bool use_exact_mappings_by_default =
132 json_details::get_bits_for<options::UseExactMappingsByDefault>(
133 PolicyFlags ) == options::UseExactMappingsByDefault::yes;
134
135 static constexpr bool must_verify_end_of_data_is_valid =
136 json_details::get_bits_for<options::MustVerifyEndOfDataIsValid>(
137 PolicyFlags ) == options::MustVerifyEndOfDataIsValid::yes;
138
139 static constexpr bool expect_long_strings =
140 json_details::get_bits_for<options::ExpectLongNames>( PolicyFlags ) ==
141 options::ExpectLongNames::yes;
142
144 switch_t<json_details::get_bits_for<options::PolicyCommentTypes,
145 std::size_t>( PolicyFlags ),
148
149 using iterator = std::conditional_t<allow_string_mutation ,
150 char *, char const *>;
151 iterator first{ };
152 iterator last{ };
153 iterator class_first{ };
154 iterator class_last{ };
155 std::size_t counter = 0;
156
157 template<auto... PolicyOptions>
159 json_details::set_bits( PolicyFlags, PolicyOptions... ), Allocator>;
160
161 explicit BasicParsePolicy( ) = default;
162
163 explicit constexpr BasicParsePolicy( iterator f, iterator l )
164 : first( f )
165 , last( l )
166 , class_first( f )
167 , class_last( l ) {}
168
169 explicit constexpr BasicParsePolicy( iterator f, iterator l,
170 Allocator &alloc )
171 : json_details::AllocatorWrapper<Allocator>( alloc )
172 , first( f )
173 , last( l )
174 , class_first( f )
175 , class_last( l ) {}
176
177 explicit constexpr BasicParsePolicy( iterator f, iterator l, iterator cf,
178 iterator cl )
179 : first( f )
180 , last( l )
181 , class_first( cf )
182 , class_last( cl ) {}
183
184 explicit constexpr BasicParsePolicy( iterator f, iterator l, iterator cf,
185 iterator cl, std::size_t cnter )
186 : first( f )
187 , last( l )
188 , class_first( cf )
189 , class_last( cl )
190 , counter( cnter ) {}
191
192 explicit constexpr BasicParsePolicy( iterator f, iterator l, iterator cf,
193 iterator cl, Allocator const &alloc )
194 : json_details::AllocatorWrapper<Allocator>( alloc )
195 , first( f )
196 , last( l )
197 , class_first( cf )
198 , class_last( cl ) {}
199
200 [[nodiscard]] constexpr BasicParsePolicy
201 copy( iterator f = iterator{ }, iterator l = iterator{ },
202 iterator cf = iterator{ }, iterator cl = iterator{ } ) const {
203 BasicParsePolicy result = *this;
204 if( f ) {
205 result.first = f;
206 }
207 if( l ) {
208 result.last = l;
209 }
210 if( cf ) {
211 result.class_first = cf;
212 }
213 if( cl ) {
214 result.class_last = cl;
215 }
216 return result;
217 }
218
219 DAW_ATTRIB_INLINE constexpr decltype( auto ) get_allocator( ) const {
220 return json_details::AllocatorWrapper<Allocator>::get_allocator( );
221 }
222
223 template<typename Alloc>
225
226 template<typename Alloc>
227 [[nodiscard]] static constexpr with_allocator_type<Alloc>
229 Alloc const &alloc ) {
230 return with_allocator_type<Alloc>{ f, l, cf, cl, alloc };
231 }
232
233 [[nodiscard]] static constexpr BasicParsePolicy
235 json_details::NoAllocator const & ) {
236 return BasicParsePolicy( f, l, cf, cl );
237 }
238
239 template<typename Alloc>
240 [[nodiscard]] constexpr auto
242 if constexpr( std::is_same_v<Alloc, json_details::NoAllocator> ) {
243 return *this;
244 } else {
245 auto result = with_allocator(
246 first, last, class_first, class_last, p.get_allocator( ) );
247 result.counter = p.counter;
248 return result;
249 }
250 }
251
252 template<typename Alloc>
253 [[nodiscard]] constexpr with_allocator_type<Alloc>
254 with_allocator( Alloc const &alloc ) const {
255 auto result =
256 with_allocator( first, last, class_first, class_last, alloc );
257 result.counter = counter;
258 return result;
259 }
260
261 [[nodiscard]] DAW_ATTRIB_INLINE constexpr auto
262 with_allocator( json_details::NoAllocator const & ) const {
263 return *this;
264 }
265
268
269 template<typename Alloc>
270 [[nodiscard]] static constexpr with_allocator_type<Alloc>
271 with_allocator( iterator f, iterator l, Alloc const &alloc ) {
272 return with_allocator_type<Alloc>{ f, l, f, l, alloc };
273 }
274
275 template<typename Alloc>
276 [[nodiscard]] static constexpr BasicParsePolicy
278 json_details::NoAllocator const & ) {
279 return BasicParsePolicy{ f, l, f, l };
280 }
281
282 [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator data( ) const {
283 return first;
284 }
285
286 [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator data_end( ) const {
287 return last;
288 }
289
290 [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator begin( ) const {
291 return first;
292 }
293
294 [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator end( ) const {
295 return last;
296 }
297
298 [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool empty( ) const {
299 if( not first ) {
300 return true;
301 }
302 if constexpr( is_zero_terminated_string ) {
303 return first >= last or *first == '\0';
304 } else {
305 return first >= last;
306 }
307 }
308
309 [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool has_more( ) const {
310#if not defined( NDEBUG )
311 daw_json_ensure( first != nullptr and last != nullptr,
312 ErrorReason::InvalidNull );
313#endif
314 return first < last;
315 }
316
317 template<std::size_t N>
318 constexpr bool starts_with( char const ( &rhs )[N] ) const {
319 static_assert( N > 0 );
320 if( size( ) < ( N - 1 ) ) {
321 return false;
322 }
323 bool result = true;
324 for( std::size_t n = 0; n < ( N - 1 ); ++n ) {
325 result = result & ( first[n] == rhs[n] );
326 }
327 return result;
328 }
329
330 template<std::size_t N>
331 constexpr bool starts_with_skip( char const ( &rhs )[N] ) {
332 if( not starts_with( rhs ) ) {
333 return false;
334 }
335 first += static_cast<std::ptrdiff_t>( N - 1 );
336 return true;
337 }
338
339 template<char c>
340 DAW_ATTRIB_INLINE constexpr void move_to_next_of_unchecked( ) {
341 auto const position =
342 json_details::memchr_unchecked<c, exec_tag_t, expect_long_strings>(
343 daw::not_null<char const *>{ daw::never_null, first },
344 daw::not_null<char const *>{ daw::never_null, last } );
345 first = json_details::input_pointer( first, position.get( ) );
346 }
347
348 template<char c>
349 DAW_ATTRIB_INLINE constexpr void move_to_next_of_checked( ) {
350 auto const position =
351 json_details::memchr_checked<c, exec_tag_t, expect_long_strings>(
352 daw::not_null<char const *>{ first },
353 daw::not_null<char const *>{ last } );
354 first = json_details::input_pointer( first, position.get( ) );
355 }
356
357 template<char c>
358 DAW_ATTRIB_INLINE constexpr void move_to_next_of( ) {
359 if( is_unchecked_input ) {
360 move_to_next_of_unchecked<c>( );
361 } else {
362 move_to_next_of_checked<c>( );
363 }
364 }
365
366 [[nodiscard]] DAW_ATTRIB_INLINE constexpr char front( ) const {
367 return *first;
368 }
369
370 [[nodiscard]] DAW_ATTRIB_INLINE constexpr char front_checked( ) const {
372 first < last, ErrorReason::UnexpectedEndOfData, *this );
373 return *first;
374 }
375
376 [[nodiscard]] DAW_ATTRIB_INLINE constexpr std::size_t size( ) const {
377 assert( last >= first );
378 return static_cast<std::size_t>( last - first );
379 }
380
381 [[nodiscard]] constexpr bool is_null( ) const {
382 return first == nullptr;
383 }
384
385 DAW_ATTRIB_INLINE constexpr void remove_prefix( ) {
386 ++first;
387 }
388
389 DAW_ATTRIB_INLINE constexpr void remove_prefix( std::size_t n ) {
390 first += static_cast<std::ptrdiff_t>( n );
391 }
392
393 constexpr void set_class_position( ) {
394 class_first = first;
395 class_last = last;
396 }
397
402
403 constexpr void set_class_position( class_pos_t new_pos ) {
404 class_first = new_pos.f;
405 class_last = new_pos.l;
406 }
407
408 [[nodiscard]] constexpr class_pos_t get_class_position( ) const {
409 return { class_first, class_last };
410 }
411
412 constexpr void trim_left_checked( ) {
413 return CommentPolicy::trim_left_checked( *this );
414 }
415
416 constexpr void trim_left_unchecked( ) {
417 return CommentPolicy::trim_left_unchecked( *this );
418 }
419
420 [[nodiscard]] constexpr bool is_literal_end( ) const {
421 return CommentPolicy::is_literal_end( *first );
422 }
423
424 [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool
426 return ( static_cast<unsigned>( static_cast<unsigned char>( *first ) ) -
427 1U ) <= 0x1FU;
428 }
429
430 [[nodiscard]] constexpr bool is_opening_bracket_checked( ) const {
431 return DAW_LIKELY( first < last ) and *first == '[';
432 }
433
434 [[nodiscard]] constexpr bool is_opening_brace_checked( ) const {
435 return DAW_LIKELY( first < last ) and *first == '{';
436 }
437
438 [[nodiscard]] constexpr bool is_closing_brace_checked( ) const {
439 return DAW_LIKELY( first < last ) and *first == '}';
440 }
441
442 [[nodiscard]] constexpr bool is_quotes_checked( ) const {
443 return DAW_LIKELY( first < last ) and *first == '"';
444 }
445
446 DAW_ATTRIB_INLINE constexpr void trim_left( ) {
447 if constexpr( is_unchecked_input ) {
448 trim_left_unchecked( );
449 } else {
450 trim_left_checked( );
451 }
452 }
453
455 trim_left_unchecked( );
456 if( *first == ',' ) {
457 ++first;
458 trim_left_unchecked( );
459 }
460 }
461
462 DAW_ATTRIB_FLATINLINE constexpr void move_next_member_or_end_checked( ) {
463 trim_left_checked( );
464 if constexpr( is_zero_terminated_string ) {
465 if( *first == ',' ) {
466 ++first;
467 trim_left( );
468 }
469 } else {
470 if( DAW_LIKELY( first < last ) and *first == ',' ) {
471 ++first;
472 trim_left( );
473 }
474 }
475 }
476
477 DAW_ATTRIB_INLINE constexpr void move_next_member_or_end( ) {
478 if constexpr( is_unchecked_input ) {
479 move_next_member_or_end_unchecked( );
480 } else {
481 move_next_member_or_end_checked( );
482 }
483 }
484
485 DAW_ATTRIB_INLINE constexpr void move_next_member( ) {
486 if constexpr( is_unchecked_input ) {
487 CommentPolicy::move_next_member_unchecked( *this );
488 } else {
489 // We have no guarantee that all members are available
490 move_next_member_or_end_checked( );
491 }
492 }
493
494 constexpr void move_to_next_class_member( ) {
495 CommentPolicy::template move_to_next_of<'"', '}'>( *this );
496 }
497
498 [[nodiscard]] constexpr bool is_at_next_class_member( ) const {
499 return parse_policy_details::in<'"', '}'>( *first );
500 }
501
502 [[nodiscard]] constexpr bool is_at_next_array_element( ) const {
503 return parse_policy_details::in<',', ']'>( *first );
504 }
505
506 [[nodiscard]] constexpr bool is_at_token_after_value( ) const {
507 return parse_policy_details::in<',', '}', ']'>( *first );
508 }
509
510 template<json_details::SkipBracketedType BracketedType>
511 [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy
513 return CommentPolicy::template skip_bracketed_item_checked<
514 BracketedType>( *this );
515 }
516
517 template<json_details::SkipBracketedType BracketedType>
518 [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy
520 return CommentPolicy::template skip_bracketed_item_unchecked<
521 BracketedType>( *this );
522 }
523
524 [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy skip_class( ) {
525#if defined( DAW_JSON_HAS_STD_SIMD )
526 if constexpr( std::is_same_v<CommentPolicy, NoCommentSkippingPolicy> ) {
527 return json_details::skip_bracketed_item_simd<
528 json_details::SkipBracketedType::Class>( *this );
529 } else
530#elif defined( DAW_JSON_HAS_SIMD )
531 if constexpr( std::is_same_v<CommentPolicy, NoCommentSkippingPolicy> ) {
532 if( not DAW_IS_CONSTANT_EVALUATED( ) ) {
533 return json_details::skip_bracketed_item_simd<
534 json_details::SkipBracketedType::Class>( *this );
535 }
536 }
537#endif
538 if constexpr( is_unchecked_input ) {
539 return skip_bracketed_item_unchecked<
540 json_details::SkipBracketedType::Class>( );
541 } else {
542 return skip_bracketed_item_checked<
543 json_details::SkipBracketedType::Class>( );
544 }
545 }
546
547 [[nodiscard]] DAW_ATTRIB_INLINE constexpr BasicParsePolicy skip_array( ) {
548#if defined( DAW_JSON_HAS_STD_SIMD )
549 if constexpr( std::is_same_v<CommentPolicy, NoCommentSkippingPolicy> ) {
550 return json_details::skip_bracketed_item_simd<
551 json_details::SkipBracketedType::Array>( *this );
552 } else
553#elif defined( DAW_JSON_HAS_SIMD )
554 if constexpr( std::is_same_v<CommentPolicy, NoCommentSkippingPolicy> ) {
555 if( not DAW_IS_CONSTANT_EVALUATED( ) ) {
556 return json_details::skip_bracketed_item_simd<
557 json_details::SkipBracketedType::Array>( *this );
558 }
559 }
560#endif
561 if constexpr( is_unchecked_input ) {
562 return skip_bracketed_item_unchecked<
563 json_details::SkipBracketedType::Array>( );
564 } else {
565 return skip_bracketed_item_checked<
566 json_details::SkipBracketedType::Array>( );
567 }
568 }
569 };
570
572
573 BasicParsePolicy( char const *, char const * ) -> BasicParsePolicy<>;
575
576 template<typename Allocator>
577 BasicParsePolicy( char const *, char const *, Allocator const & )
579 template<typename Allocator>
580 BasicParsePolicy( char *, char *, Allocator const & )
582
583 BasicParsePolicy( char const *, char const *, char const *, char const * )
585 BasicParsePolicy( char *, char *, char *, char * ) -> BasicParsePolicy<>;
586
587 template<typename Allocator>
588 BasicParsePolicy( char const *, char const *, char const *, char const *,
589 Allocator const & )
591 template<typename Allocator>
592 BasicParsePolicy( char *, char *, char *, char *, Allocator const & )
594
596 : BasicParsePolicy<json_details::default_policy_flag,
597 json_details::NoAllocator> {
598
599 using BasicParsePolicy::BasicParsePolicy;
600
601 constexpr DefaultParsePolicy( BasicParsePolicy const &other ) noexcept
602 : BasicParsePolicy( other ) {}
603 constexpr DefaultParsePolicy( BasicParsePolicy &&other ) noexcept
604 : BasicParsePolicy( std::move( other ) ) {}
605 };
606
607 template<json_options_t PolicyFlags = json_details::default_policy_flag,
608 typename Allocator = json_details::NoAllocator>
610 daw::conditional_t<(PolicyFlags == json_details::default_policy_flag and
611 std::is_same_v<Allocator, json_details::NoAllocator>),
614 template<typename ParsePolicy>
616 daw::conditional_t<ParsePolicy::is_default_parse_policy,
617 DefaultParsePolicy, ParsePolicy>;
618
619 namespace options {
620 /***
621 * @brief Specify parse policy flags in to_json calls. See cookbook item
622 * parse_options.md
623 */
624 template<auto... PolicyFlags>
626 static_assert(
627 json_details::are_option_flags<decltype( PolicyFlags )...>,
628 "Only registered policy types are allowed" );
629 static constexpr json_options_t value = parse_options( PolicyFlags... );
630 };
631 template<>
632 struct parse_flags_t<> {
633 static constexpr json_options_t value =
634 json_details::default_policy_flag;
635 };
636
637 namespace details {
638 template<typename... Ts>
639 std::false_type is_policy_flag( Ts... );
640
641 template<auto... PolicyFlags>
643
644 template<auto... PolicyFlags>
645 DAW_CONSTEVAL auto make_parse_flags( ) {
646 if constexpr( decltype( details::is_policy_flag(
647 PolicyFlags... ) )::value ) {
648 static_assert( sizeof...( PolicyFlags ) == 1 );
649 // We know there is only one but need to unpack
650 return ( PolicyFlags, ... );
651 } else {
652 return parse_flags_t<PolicyFlags...>{ };
653 }
654 }
655 } // namespace details
660 template<auto... PolicyFlags>
661 inline constexpr auto parse_flags =
662 details::make_parse_flags<PolicyFlags...>( );
663 } // namespace options
664
665#define DAW_JSON_CONFORMANCE_FLAGS \
666 daw::json::options::AllowEscapedNames::yes, \
667 daw::json::options::MustVerifyEndOfDataIsValid::yes, \
668 daw::json::options::IEEE754Precise::yes, \
669 daw::json::options::ExcludeSpecialEscapes::yes
670
671 inline constexpr auto ConformancePolicy =
672 options::parse_flags<DAW_JSON_CONFORMANCE_FLAGS>;
673
674 } // namespace DAW_JSON_VER
675} // namespace daw::json
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
constexpr auto parse_flags
Specify parse policy flags in to_json calls. See cookbook item parse_options.md.
daw::conditional_t<(PolicyFlags==json_details::default_policy_flag and std::is_same_v< Allocator, json_details::NoAllocator >), DefaultParsePolicy, BasicParsePolicy< PolicyFlags, Allocator > > GetParsePolicy
daw::conditional_t< ParsePolicy::is_default_parse_policy, DefaultParsePolicy, ParsePolicy > TryDefaultParsePolicy
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
Customization point traits.
Handles the bounds and policy items for parsing execution and comments.
static constexpr BasicParsePolicy with_allocator(iterator f, iterator l, iterator cf, iterator cl, json_details::NoAllocator const &)
constexpr BasicParsePolicy(iterator f, iterator l, iterator cf, iterator cl, Allocator const &alloc)
constexpr BasicParsePolicy(iterator f, iterator l, iterator cf, iterator cl)
DAW_ATTRIB_INLINE constexpr auto with_allocator(json_details::NoAllocator const &) const
constexpr auto with_allocator(BasicParsePolicy< PolicyFlags, Alloc > p) const
static constexpr BasicParsePolicy with_allocator(iterator f, iterator l, json_details::NoAllocator const &)
switch_t< json_details::get_bits_for< options::ExecModeTypes, std::size_t >(PolicyFlags), default_exec_tag, constexpr_exec_tag, runtime_exec_tag, simd_exec_tag > exec_tag_t
constexpr BasicParsePolicy copy(iterator f=iterator{ }, iterator l=iterator{ }, iterator cf=iterator{ }, iterator cl=iterator{ }) const
constexpr BasicParsePolicy(iterator f, iterator l, iterator cf, iterator cl, std::size_t cnter)
constexpr BasicParsePolicy(iterator f, iterator l, Allocator &alloc)
static constexpr with_allocator_type< Alloc > with_allocator(iterator f, iterator l, Alloc const &alloc)
static constexpr with_allocator_type< Alloc > with_allocator(iterator f, iterator l, iterator cf, iterator cl, Alloc const &alloc)
switch_t< json_details::get_bits_for< options::PolicyCommentTypes, std::size_t >(PolicyFlags), NoCommentSkippingPolicy, CppCommentSkippingPolicy, HashCommentSkippingPolicy > CommentPolicy
constexpr with_allocator_type< Alloc > with_allocator(Alloc const &alloc) const
std::conditional_t< allow_string_mutation, char *, char const * > iterator
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20