DAW JSON Link
Loading...
Searching...
No Matches
daw_json_simd_iterator_class.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
13
14#if defined( DAW_JSON_HAS_SIMD )
15
20
21#include <cstddef>
22#include <cstdint>
23#include <iterator>
24#include <string_view>
25#include <type_traits>
26
27namespace daw::json {
28 inline namespace DAW_JSON_VER {
29 namespace json_details::simd_details {
35 struct simd_class_structural_state {
36 using simd_type = daw::simd::vec<char>;
37 static constexpr std::size_t block_size =
38 static_cast<std::size_t>( simd_type::size( ) );
39 static_assert( block_size <= 64U );
40
41 char const *next_block = nullptr;
42 char const *last = nullptr;
43 char const *block_data = nullptr;
44 std::size_t block_length = 0U;
45 // Structural characters plus the value metadata stage 2 needs without
46 // rescanning: string escapes and real-number separators.
47 std::uint64_t structural_offsets = 0U;
48 bool in_string = false;
49 bool escaped = false;
50
51 constexpr void reset( char const *first, char const *last_ptr ) {
52 next_block = first;
53 last = last_ptr;
54 block_data = nullptr;
55 block_length = 0U;
56 structural_offsets = 0U;
57 in_string = false;
58 escaped = false;
59 }
60
61 private:
62 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR bool classify_next_block( ) {
63 if( next_block == nullptr or next_block >= last ) {
64 return false;
65 }
66
67 block_data = next_block;
68 auto const remaining = static_cast<std::size_t>( last - next_block );
69 block_length = remaining < block_size ? remaining : block_size;
70 auto const input = simd_details::load<simd_type, block_size, char>(
71 block_data, block_length );
72 auto const valid_bits = simd_details::low_bits( block_length );
73 auto const backslash_bits =
74 ( input == simd_details::splat<simd_type>( '\\' ) ).to_ullong( ) &
75 valid_bits;
76
77 DAW_CPP23_STATIC_LOCAL constexpr std::uint64_t odd_bits =
78 0xAAAAAAAAAAAAAAAAULL;
79 auto const previous_escaped = escaped ? std::uint64_t{ 1 } : 0U;
80 auto const potential_escape = backslash_bits & ~previous_escaped;
81 auto const maybe_escaped = potential_escape << 1U;
82 auto const escape_and_terminal =
83 ( ( maybe_escaped | odd_bits ) - potential_escape ) ^ odd_bits;
84 auto const escaped_bits =
85 ( escape_and_terminal ^ ( backslash_bits | previous_escaped ) ) &
86 valid_bits;
87 auto const escape_bits = escape_and_terminal & backslash_bits;
88 escaped = simd_details::last_bit( escape_bits, block_length );
89
90 auto const quote_bits =
91 ( input == simd_details::splat<simd_type>( '"' ) ).to_ullong( ) &
92 ~escaped_bits & valid_bits;
93 auto const in_string_bits =
94 ( simd_details::prefix_xor( quote_bits ) ^
95 ( in_string ? valid_bits : std::uint64_t{ 0 } ) ) &
96 valid_bits;
97 in_string = simd_details::last_bit( in_string_bits, block_length );
98
99 auto const outside_string_bits =
100 ~( in_string_bits ^ quote_bits ) & valid_bits;
101 auto const json_structurals =
102 simd_details::one_of<'{', '}', '[', ']', ':', ','>( input )
103 .to_ullong( ) &
104 outside_string_bits;
105 auto const number_metadata =
106 simd_details::one_of<'.', 'e', 'E'>( input ).to_ullong( ) &
107 outside_string_bits;
108 structural_offsets =
109 quote_bits | backslash_bits | json_structurals | number_metadata;
110 next_block += static_cast<std::ptrdiff_t>( block_length );
111 return true;
112 }
113
114 public:
115 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR char const *
116 next( char const *minimum ) {
117 while( true ) {
118 while( structural_offsets != 0U ) {
119 auto const lane = static_cast<std::size_t>(
120 daw::cxmath::count_trailing_zeros( structural_offsets ) );
121 structural_offsets &= structural_offsets - 1U;
122 auto const result = block_data + lane;
123 if( result >= minimum ) {
124 return result;
125 }
126 }
127 if( not classify_next_block( ) ) {
128 return nullptr;
129 }
130 }
131 }
132 };
133
134 [[nodiscard]] constexpr bool is_json_whitespace( char value ) noexcept {
135 return value == ' ' or value == '\t' or value == '\n' or value == '\r';
136 }
137
138 [[nodiscard]] constexpr char const *
139 trim_value_right( char const *first, char const *last ) noexcept {
140 while( last > first and is_json_whitespace( last[-1] ) ) {
141 --last;
142 }
143 return last;
144 }
145
146 template<std::size_t N>
147 [[nodiscard]] constexpr bool
148 matches_literal( char const *first, char const *last,
149 char const ( &literal )[N] ) noexcept {
150 if( static_cast<std::size_t>( last - first ) != N - 1U ) {
151 return false;
152 }
153 for( std::size_t n = 0; n < N - 1U; ++n ) {
154 if( first[n] != literal[n] ) {
155 return false;
156 }
157 }
158 return true;
159 }
160
161 template<typename JsonMemberList>
162 struct simd_class_parser;
163
164 template<typename... JsonMembers>
165 struct simd_class_parser<json_member_list<JsonMembers...>> {
166 template<typename ParseState>
167 using locations_type =
168 decltype( make_locations_info<ParseState, JsonMembers...>( ) );
169
170 template<typename ParseState>
171 [[nodiscard]] static constexpr locations_type<ParseState>
172 make_locations( ) {
173 return make_locations_info<ParseState, JsonMembers...>( );
174 }
175
176 template<typename JsonClass, typename ParseState>
177 [[nodiscard]] static DAW_JSON_SIMD_CONSTEXPR char const *
178 scan_class( ParseState &parse_state,
179 locations_type<ParseState> &locations,
180 simd_class_structural_state &structural_state ) {
181 using result_t = json_result_t<JsonClass>;
182 DAW_CPP23_STATIC_LOCAL constexpr bool must_exist =
183 all_json_members_must_exist_v<result_t, ParseState>;
184
185 parse_state.trim_left( );
186 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
187 ErrorReason::InvalidClassStart,
188 parse_state );
189 auto const old_class_pos = parse_state.get_class_position( );
190 auto const class_first = parse_state.data( );
191 auto const class_last = parse_state.data_end( );
192 parse_state.set_class_position( );
193
194 auto event = structural_state.next( class_first );
195 daw_json_assert_weak( event != nullptr and *event == '{',
196 ErrorReason::InvalidClassStart,
197 parse_state );
198 event = structural_state.next( event + 1 );
199 auto after_comma = false;
200
201 while( event != nullptr and *event != '}' ) {
202 daw_json_assert_weak( *event == '"',
203 ErrorReason::InvalidMemberName,
204 parse_state );
205 auto const name_first = event + 1;
206 auto name_last = structural_state.next( name_first );
207 while( name_last != nullptr and *name_last == '\\' ) {
208 name_last = structural_state.next( name_last + 1 );
209 }
210 daw_json_assert_weak( name_last != nullptr and *name_last == '"',
211 ErrorReason::InvalidMemberName,
212 parse_state );
213 auto const name = daw::string_view(
214 name_first, static_cast<std::size_t>( name_last - name_first ) );
215 auto const name_pos =
216 locations.template find_name<ParseState::expect_long_strings, 0>(
217 name );
218 if constexpr( must_exist ) {
219 daw_json_assert_weak( name_pos < locations.size( ),
220 ErrorReason::UnknownMember,
221 parse_state );
222 }
223 auto const colon = structural_state.next( name_last + 1 );
224 daw_json_assert_weak( colon != nullptr and *colon == ':',
225 ErrorReason::InvalidMemberName,
226 parse_state );
227 auto value_state = ParseState( colon + 1, class_last );
228 value_state.trim_left( );
229 auto const value_first = value_state.data( );
230 daw_json_assert_weak( value_first < class_last,
231 ErrorReason::UnexpectedEndOfData,
232 parse_state );
233
234 auto object_depth = std::size_t{ 1 };
235 auto array_depth = std::size_t{ 0 };
236 auto container_count = std::size_t{ 0 };
237 char const *first_escape = nullptr;
238 char const *string_last = nullptr;
239 char const *decimal_point = nullptr;
240 char const *exponent_marker = nullptr;
241 auto const value_is_string = *value_first == '"';
242 auto const value_is_array = *value_first == '[';
243 auto const value_is_class = *value_first == '{';
244 auto const value_is_number =
245 *value_first == '-' or
246 ( *value_first >= '0' and *value_first <= '9' );
247 auto delimiter = structural_state.next( colon + 1 );
248 auto found_delimiter = false;
249 while( value_is_number and delimiter != nullptr and
250 not found_delimiter ) {
251 switch( *delimiter ) {
252 case '.':
253 if( decimal_point == nullptr ) {
254 decimal_point = delimiter;
255 }
256 break;
257 case 'e':
258 case 'E':
259 if( exponent_marker == nullptr ) {
260 exponent_marker = delimiter;
261 }
262 break;
263 default:
264 found_delimiter = true;
265 break;
266 }
267 if( not found_delimiter ) {
268 delimiter = structural_state.next( delimiter + 1 );
269 }
270 }
271 while( not value_is_number and delimiter != nullptr and
272 not found_delimiter ) {
273 switch( *delimiter ) {
274 case '"':
275 if( value_is_string and delimiter != value_first and
276 string_last == nullptr ) {
277 string_last = delimiter;
278 }
279 break;
280 case '\\':
281 if( value_is_string and first_escape == nullptr ) {
282 first_escape = delimiter;
283 }
284 break;
285 case '{':
286 ++object_depth;
287 break;
288 case '}':
289 if( object_depth == 1U and array_depth == 0U ) {
290 found_delimiter = true;
291 break;
292 }
293 daw_json_assert_weak( object_depth > 1U,
294 ErrorReason::InvalidBracketing,
295 parse_state );
296 --object_depth;
297 break;
298 case '[':
299 ++array_depth;
300 break;
301 case ']':
302 daw_json_assert_weak( array_depth > 0U,
303 ErrorReason::InvalidBracketing,
304 parse_state );
305 --array_depth;
306 break;
307 case ',':
308 if( ( value_is_array and object_depth == 1U and
309 array_depth == 1U ) or
310 ( value_is_class and object_depth == 2U and
311 array_depth == 0U ) ) {
312 ++container_count;
313 }
314 if( object_depth == 1U and array_depth == 0U ) {
315 found_delimiter = true;
316 }
317 break;
318 default:
319 break;
320 }
321 if( not found_delimiter ) {
322 delimiter = structural_state.next( delimiter + 1 );
323 }
324 }
325
326 daw_json_assert_weak( delimiter != nullptr,
327 ErrorReason::UnexpectedEndOfData,
328 parse_state );
329 auto const value_last =
330 trim_value_right( value_first, delimiter );
331 daw_json_assert_weak( value_first < value_last,
332 ErrorReason::InvalidStartOfValue,
333 parse_state );
334 if constexpr( not ParseState::is_unchecked_input ) {
335 switch( *value_first ) {
336 case 't':
338 matches_literal( value_first, value_last, "true" ),
339 ErrorReason::InvalidTrue,
340 parse_state );
341 break;
342 case 'f':
344 matches_literal( value_first, value_last, "false" ),
345 ErrorReason::InvalidFalse,
346 parse_state );
347 break;
348 case 'n':
350 matches_literal( value_first, value_last, "null" ),
351 ErrorReason::InvalidNull,
352 parse_state );
353 break;
354 default:
355 break;
356 }
357 }
358
359 if( name_pos < locations.size( ) and
360 locations[name_pos].missing( ) ) {
361 auto location_state = ParseState(
362 value_first, value_last, class_first, class_last );
363 switch( *value_first ) {
364 case '"':
365 daw_json_assert_weak( string_last != nullptr and
366 string_last + 1 == value_last,
367 ErrorReason::InvalidString,
368 parse_state );
369 location_state.first = value_first + 1;
370 location_state.last = string_last;
371 location_state.counter =
372 first_escape == nullptr
373 ? static_cast<std::size_t>( -1 )
374 : static_cast<std::size_t>( first_escape - ( value_first + 1 ) );
375 break;
376 case 't':
377 location_state.counter = 1U;
378 break;
379 case 'f':
380 location_state.counter = 0U;
381 break;
382 case 'n':
383 location_state.first = nullptr;
384 location_state.last = nullptr;
385 break;
386 case '[':
387 case '{':
388 location_state.counter = container_count;
389 break;
390 default:
391 location_state.class_first = decimal_point;
392 location_state.class_last = exponent_marker;
393 break;
394 }
395 locations[name_pos].set_range( location_state );
396 } else if constexpr( must_exist ) {
397 daw_json_error( true, ErrorReason::UnknownMember, parse_state );
398 }
399
400 after_comma = *delimiter == ',';
401 event = after_comma
402 ? structural_state.next( delimiter + 1 )
403 : delimiter;
404 }
405
406 daw_json_assert_weak( event != nullptr,
407 ErrorReason::UnexpectedEndOfData,
408 parse_state );
409 daw_json_assert_weak( not after_comma,
410 ErrorReason::TrailingComma,
411 parse_state );
412 daw_json_assert_weak( *event == '}',
413 ErrorReason::InvalidEndOfValue,
414 parse_state );
415 auto const class_end = event + 1;
416 parse_state.first = class_end;
417 parse_state.trim_left_checked( );
418 parse_state.set_class_position( old_class_pos );
419 return class_end;
420 }
421
422 private:
423 template<typename JsonMember, typename ParseState, typename Location>
424 [[nodiscard]] static constexpr json_result_t<JsonMember>
425 parse_member( ParseState &parse_state, Location const &location ) {
426 auto member_state = [&] {
427 if constexpr( ParseState::has_allocator ) {
428 return location.template get_range<ParseState>( ).with_allocator(
429 parse_state );
430 } else {
431 return location.template get_range<ParseState>( );
432 }
433 }( );
434 if( member_state.is_null( ) ) {
435 // A stored null and a missing member intentionally use the same null
436 // location representation. Preserve nullable/missing-member handling.
437 return parse_class_member_impl<JsonMember, false>(
438 parse_state, find_result<ParseState>{ member_state, true } );
439 }
440 return parse_value<without_name<JsonMember>,
441 true,
442 JsonMember::expected_type>( member_state );
443 }
444
445 template<typename JsonClass, typename ParseState, std::size_t... Is>
446 [[nodiscard]] static constexpr json_result_t<JsonClass>
447 construct_class_impl( ParseState &parse_state,
448 locations_type<ParseState> const &locations,
449 std::index_sequence<Is...> ) {
450 using result_t = json_result_t<JsonClass>;
451 using constructor_t = json_constructor_t<JsonClass>;
452 if constexpr( should_construct_explicitly_v<constructor_t,
453 result_t,
454 ParseState> ) {
455 return result_t{
456 parse_member<JsonMembers>( parse_state, locations[Is] )... };
457 } else {
458 return construct_value_tp<result_t, constructor_t>(
459 parse_state,
460 fwd_pack{
461 parse_member<JsonMembers>( parse_state, locations[Is] )... } );
462 }
463 }
464
465 public:
466 template<typename JsonClass, typename ParseState>
467 [[nodiscard]] static constexpr json_result_t<JsonClass>
468 construct_class( ParseState &parse_state,
469 locations_type<ParseState> const &locations ) {
470 return construct_class_impl<JsonClass>(
471 parse_state,
472 locations,
473 std::index_sequence_for<JsonMembers...>{ } );
474 }
475 };
476
477 template<>
478 struct simd_class_parser<json_member_list<>> {
479 struct empty_locations {};
480
481 template<typename ParseState>
482 using locations_type = empty_locations;
483
484 template<typename ParseState>
485 [[nodiscard]] static constexpr locations_type<ParseState>
486 make_locations( ) {
487 return { };
488 }
489
490 template<typename JsonClass, typename ParseState>
491 [[nodiscard]] static DAW_JSON_SIMD_CONSTEXPR char const *
492 scan_class( ParseState &parse_state, empty_locations &,
493 simd_class_structural_state &structural_state ) {
494 using result_t = json_result_t<JsonClass>;
495 parse_state.trim_left( );
496 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
497 ErrorReason::InvalidClassStart,
498 parse_state );
499 auto const old_class_pos = parse_state.get_class_position( );
500 auto const class_first = parse_state.data( );
501 parse_state.set_class_position( );
502 auto event = structural_state.next( class_first );
503 daw_json_assert_weak( event != nullptr and *event == '{',
504 ErrorReason::InvalidClassStart,
505 parse_state );
506 event = structural_state.next( event + 1 );
507 if constexpr( all_json_members_must_exist_v<result_t, ParseState> ) {
508 daw_json_assert_weak( event != nullptr and *event == '}',
509 ErrorReason::UnknownMember,
510 parse_state );
511 } else {
512 auto object_depth = std::size_t{ 1 };
513 auto array_depth = std::size_t{ 0 };
514 auto found_end = false;
515 while( event != nullptr and not found_end ) {
516 switch( *event ) {
517 case '{':
518 ++object_depth;
519 break;
520 case '}':
521 if( object_depth == 1U and array_depth == 0U ) {
522 found_end = true;
523 break;
524 }
525 daw_json_assert_weak( object_depth > 1U,
526 ErrorReason::InvalidBracketing,
527 parse_state );
528 --object_depth;
529 break;
530 case '[':
531 ++array_depth;
532 break;
533 case ']':
534 daw_json_assert_weak( array_depth > 0U,
535 ErrorReason::InvalidBracketing,
536 parse_state );
537 --array_depth;
538 break;
539 default:
540 break;
541 }
542 if( not found_end ) {
543 event = structural_state.next( event + 1 );
544 }
545 }
546 daw_json_assert_weak( event != nullptr,
547 ErrorReason::UnexpectedEndOfData,
548 parse_state );
549 }
550 auto const class_end = event + 1;
551 parse_state.first = class_end;
552 parse_state.trim_left_checked( );
553 parse_state.set_class_position( old_class_pos );
554 return class_end;
555 }
556
557 template<typename JsonClass, typename ParseState>
558 [[nodiscard]] static constexpr json_result_t<JsonClass>
559 construct_class( ParseState &parse_state, empty_locations const & ) {
560 using result_t = json_result_t<JsonClass>;
561 using constructor_t = json_constructor_t<JsonClass>;
562 if constexpr( should_construct_explicitly_v<constructor_t,
563 result_t,
564 ParseState> ) {
565 return result_t{ };
566 } else {
567 return construct_value_tp<result_t, constructor_t>( parse_state,
568 fwd_pack{ } );
569 }
570 }
571 };
572
573 template<typename Locations>
574 struct simd_class_value_state {
575 char const *first = nullptr;
576 char const *last = nullptr;
577 Locations locations;
578 };
579
580 template<typename JsonMember, typename CharT, auto... PolicyFlags>
581 class json_simd_block_iterator_class {
582 static_assert( JsonMember::underlying_json_type ==
583 JsonBaseParseTypes::Class );
584 static_assert(
585 std::is_same_v<CharT, char>,
586 "SIMD class iteration currently supports char input only" );
587
588 using ParseState = TryDefaultParsePolicy<BasicParsePolicy<
589 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
590 using parser_type =
591 simd_class_parser<typename JsonMember::json_member_list>;
592 using locations_type =
593 typename parser_type::template locations_type<ParseState>;
594 using value_state_type = simd_class_value_state<locations_type>;
595
596 public:
597 using json_member = JsonMember;
598 using value_type = typename json_member::parse_to_t;
599 using reference = value_type;
600 using difference_type = std::ptrdiff_t;
601 using iterator_category = std::input_iterator_tag;
602
603 private:
604 char const *m_first = nullptr;
605 char const *m_last = nullptr;
606 bool m_previous_value = false;
607 simd_class_structural_state m_structural_state{ };
608 value_state_type m_current{
609 nullptr,
610 nullptr,
611 parser_type::template make_locations<ParseState>( ) };
612
613 constexpr void move_to_next_value( ) {
614 m_current.first = nullptr;
615 m_current.last = nullptr;
616 if( m_first == nullptr or m_first == m_last ) {
617 return;
618 }
619
620 auto parse_state = ParseState( m_first, m_last );
621 parse_state.trim_left( );
622 if( parse_state.empty( ) ) {
623 m_first = m_last;
624 return;
625 }
626
627 if( m_previous_value ) {
628 if( parse_state.front( ) == ']' ) {
629 parse_state.remove_prefix( );
630 m_first = m_last;
631 return;
632 }
633 daw_json_assert_weak( parse_state.front( ) == ',',
634 ErrorReason::InvalidEndOfValue,
635 parse_state );
636 parse_state.remove_prefix( );
637 parse_state.trim_left( );
638 daw_json_assert_weak( not parse_state.empty( ) and
639 parse_state.front( ) != ']',
640 ErrorReason::TrailingComma,
641 parse_state );
642 } else if( parse_state.front( ) == ']' ) {
643 parse_state.remove_prefix( );
644 m_first = m_last;
645 return;
646 }
647
648 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
649 ErrorReason::InvalidClassStart,
650 parse_state );
651 m_current.first = parse_state.data( );
652 m_current.locations =
653 parser_type::template make_locations<ParseState>( );
654 m_current.last = parser_type::template scan_class<JsonMember>(
655 parse_state, m_current.locations, m_structural_state );
656 m_first = parse_state.data( );
657 m_previous_value = true;
658 }
659
660 public:
661 constexpr json_simd_block_iterator_class( ) = default;
662
663 explicit constexpr json_simd_block_iterator_class(
664 std::string_view document )
665 : m_first( document.data( ) )
666 , m_last( std::next( document.data( ), static_cast<std::ptrdiff_t>(
667 document.size( ) ) ) ) {
668 if( m_first != m_last ) {
669 auto parse_state = ParseState( m_first, m_last );
670 parse_state.trim_left( );
671 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
672 ErrorReason::InvalidArrayStart,
673 parse_state );
674 parse_state.remove_prefix( );
675 m_first = parse_state.data( );
676 m_structural_state.reset( m_first, m_last );
677 }
678 move_to_next_value( );
679 }
680
681 explicit constexpr json_simd_block_iterator_class(
682 std::string_view document, daw::string_view start_path )
683 : json_simd_block_iterator_class(
684 find_array_range<ParseState>( document, start_path ) ) {}
685
686 [[nodiscard]] constexpr reference operator*( ) const {
687 auto parse_state = ParseState( m_current.first, m_current.last );
688 parse_state.first = m_current.last;
689 return parser_type::template construct_class<json_member>(
690 parse_state, m_current.locations );
691 }
692
693 constexpr json_simd_block_iterator_class &operator++( ) {
694 move_to_next_value( );
695 return *this;
696 }
697
698 constexpr void operator++( int ) {
699 (void)operator++( );
700 }
701
702 [[nodiscard]] constexpr explicit operator bool( ) const noexcept {
703 return m_current.first != nullptr;
704 }
705
706 [[nodiscard]] constexpr json_simd_block_iterator_class begin( ) const {
707 return *this;
708 }
709
710 [[nodiscard]] constexpr json_simd_block_iterator_class static end( ) noexcept {
711 return { };
712 }
713
714 friend constexpr bool
715 operator==( json_simd_block_iterator_class const &lhs,
716 json_simd_block_iterator_class const &rhs ) noexcept {
717 auto const lhs_at_end = not lhs;
718 auto const rhs_at_end = not rhs;
719 if( lhs_at_end or rhs_at_end ) {
720 return lhs_at_end == rhs_at_end;
721 }
722 return lhs.m_current.first == rhs.m_current.first;
723 }
724
725 friend constexpr bool
726 operator!=( json_simd_block_iterator_class const &lhs,
727 json_simd_block_iterator_class const &rhs ) noexcept {
728 return not( lhs == rhs );
729 }
730 };
731 } // namespace json_details::simd_details
732 } // namespace DAW_JSON_VER
733} // namespace daw::json
734
735#endif
#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
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20