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<0>( name );
217 if constexpr( must_exist ) {
218 daw_json_assert_weak( name_pos < locations.size( ),
219 ErrorReason::UnknownMember,
220 parse_state );
221 }
222 auto const colon = structural_state.next( name_last + 1 );
223 daw_json_assert_weak( colon != nullptr and *colon == ':',
224 ErrorReason::InvalidMemberName,
225 parse_state );
226 auto value_state = ParseState( colon + 1, class_last );
227 value_state.trim_left( );
228 auto const value_first = value_state.data( );
229 daw_json_assert_weak( value_first < class_last,
230 ErrorReason::UnexpectedEndOfData,
231 parse_state );
232
233 auto object_depth = std::size_t{ 1 };
234 auto array_depth = std::size_t{ 0 };
235 auto container_count = std::size_t{ 0 };
236 char const *first_escape = nullptr;
237 char const *string_last = nullptr;
238 char const *decimal_point = nullptr;
239 char const *exponent_marker = nullptr;
240 auto const value_is_string = *value_first == '"';
241 auto const value_is_array = *value_first == '[';
242 auto const value_is_class = *value_first == '{';
243 auto const value_is_number =
244 *value_first == '-' or
245 ( *value_first >= '0' and *value_first <= '9' );
246 auto delimiter = structural_state.next( colon + 1 );
247 auto found_delimiter = false;
248 while( value_is_number and delimiter != nullptr and
249 not found_delimiter ) {
250 switch( *delimiter ) {
251 case '.':
252 if( decimal_point == nullptr ) {
253 decimal_point = delimiter;
254 }
255 break;
256 case 'e':
257 case 'E':
258 if( exponent_marker == nullptr ) {
259 exponent_marker = delimiter;
260 }
261 break;
262 default:
263 found_delimiter = true;
264 break;
265 }
266 if( not found_delimiter ) {
267 delimiter = structural_state.next( delimiter + 1 );
268 }
269 }
270 while( not value_is_number and delimiter != nullptr and
271 not found_delimiter ) {
272 switch( *delimiter ) {
273 case '"':
274 if( value_is_string and delimiter != value_first and
275 string_last == nullptr ) {
276 string_last = delimiter;
277 }
278 break;
279 case '\\':
280 if( value_is_string and first_escape == nullptr ) {
281 first_escape = delimiter;
282 }
283 break;
284 case '{':
285 ++object_depth;
286 break;
287 case '}':
288 if( object_depth == 1U and array_depth == 0U ) {
289 found_delimiter = true;
290 break;
291 }
292 daw_json_assert_weak( object_depth > 1U,
293 ErrorReason::InvalidBracketing,
294 parse_state );
295 --object_depth;
296 break;
297 case '[':
298 ++array_depth;
299 break;
300 case ']':
301 daw_json_assert_weak( array_depth > 0U,
302 ErrorReason::InvalidBracketing,
303 parse_state );
304 --array_depth;
305 break;
306 case ',':
307 if( ( value_is_array and object_depth == 1U and
308 array_depth == 1U ) or
309 ( value_is_class and object_depth == 2U and
310 array_depth == 0U ) ) {
311 ++container_count;
312 }
313 if( object_depth == 1U and array_depth == 0U ) {
314 found_delimiter = true;
315 }
316 break;
317 default:
318 break;
319 }
320 if( not found_delimiter ) {
321 delimiter = structural_state.next( delimiter + 1 );
322 }
323 }
324
325 daw_json_assert_weak( delimiter != nullptr,
326 ErrorReason::UnexpectedEndOfData,
327 parse_state );
328 auto const value_last =
329 trim_value_right( value_first, delimiter );
330 daw_json_assert_weak( value_first < value_last,
331 ErrorReason::InvalidStartOfValue,
332 parse_state );
333 if constexpr( not ParseState::is_unchecked_input ) {
334 switch( *value_first ) {
335 case 't':
337 matches_literal( value_first, value_last, "true" ),
338 ErrorReason::InvalidTrue,
339 parse_state );
340 break;
341 case 'f':
343 matches_literal( value_first, value_last, "false" ),
344 ErrorReason::InvalidFalse,
345 parse_state );
346 break;
347 case 'n':
349 matches_literal( value_first, value_last, "null" ),
350 ErrorReason::InvalidNull,
351 parse_state );
352 break;
353 default:
354 break;
355 }
356 }
357
358 if( name_pos < locations.size( ) and
359 locations[name_pos].missing( ) ) {
360 auto location_state = ParseState(
361 value_first, value_last, class_first, class_last );
362 switch( *value_first ) {
363 case '"':
364 daw_json_assert_weak( string_last != nullptr and
365 string_last + 1 == value_last,
366 ErrorReason::InvalidString,
367 parse_state );
368 location_state.first = value_first + 1;
369 location_state.last = string_last;
370 location_state.counter =
371 first_escape == nullptr
372 ? static_cast<std::size_t>( -1 )
373 : static_cast<std::size_t>( first_escape - ( value_first + 1 ) );
374 break;
375 case 't':
376 location_state.counter = 1U;
377 break;
378 case 'f':
379 location_state.counter = 0U;
380 break;
381 case 'n':
382 location_state.first = nullptr;
383 location_state.last = nullptr;
384 break;
385 case '[':
386 case '{':
387 location_state.counter = container_count;
388 break;
389 default:
390 location_state.class_first = decimal_point;
391 location_state.class_last = exponent_marker;
392 break;
393 }
394 locations[name_pos].set_range( location_state );
395 } else if constexpr( must_exist ) {
396 daw_json_error( true, ErrorReason::UnknownMember, parse_state );
397 }
398
399 after_comma = *delimiter == ',';
400 event = after_comma
401 ? structural_state.next( delimiter + 1 )
402 : delimiter;
403 }
404
405 daw_json_assert_weak( event != nullptr,
406 ErrorReason::UnexpectedEndOfData,
407 parse_state );
408 daw_json_assert_weak( not after_comma,
409 ErrorReason::TrailingComma,
410 parse_state );
411 daw_json_assert_weak( *event == '}',
412 ErrorReason::InvalidEndOfValue,
413 parse_state );
414 auto const class_end = event + 1;
415 parse_state.first = class_end;
416 parse_state.trim_left_checked( );
417 parse_state.set_class_position( old_class_pos );
418 return class_end;
419 }
420
421 private:
422 template<typename JsonMember, typename ParseState, typename Location>
423 [[nodiscard]] static constexpr json_result_t<JsonMember>
424 parse_member( ParseState &parse_state, Location const &location ) {
425 auto member_state = [&] {
426 if constexpr( ParseState::has_allocator ) {
427 return location.template get_range<ParseState>( ).with_allocator(
428 parse_state );
429 } else {
430 return location.template get_range<ParseState>( );
431 }
432 }( );
433 if( member_state.is_null( ) ) {
434 // A stored null and a missing member intentionally use the same null
435 // location representation. Preserve nullable/missing-member handling.
436 return parse_class_member_impl<JsonMember, false>(
437 parse_state, find_result<ParseState>{ member_state, true } );
438 }
439 return parse_value<without_name<JsonMember>,
440 true,
441 JsonMember::expected_type>( member_state );
442 }
443
444 template<typename JsonClass, typename ParseState, std::size_t... Is>
445 [[nodiscard]] static constexpr json_result_t<JsonClass>
446 construct_class_impl( ParseState &parse_state,
447 locations_type<ParseState> const &locations,
448 std::index_sequence<Is...> ) {
449 using result_t = json_result_t<JsonClass>;
450 using constructor_t = json_constructor_t<JsonClass>;
451 if constexpr( should_construct_explicitly_v<constructor_t,
452 result_t,
453 ParseState> ) {
454 return result_t{
455 parse_member<JsonMembers>( parse_state, locations[Is] )... };
456 } else {
457 return construct_value_tp<result_t, constructor_t>(
458 parse_state,
459 fwd_pack{
460 parse_member<JsonMembers>( parse_state, locations[Is] )... } );
461 }
462 }
463
464 public:
465 template<typename JsonClass, typename ParseState>
466 [[nodiscard]] static constexpr json_result_t<JsonClass>
467 construct_class( ParseState &parse_state,
468 locations_type<ParseState> const &locations ) {
469 return construct_class_impl<JsonClass>(
470 parse_state,
471 locations,
472 std::index_sequence_for<JsonMembers...>{ } );
473 }
474 };
475
476 template<>
477 struct simd_class_parser<json_member_list<>> {
478 struct empty_locations {};
479
480 template<typename ParseState>
481 using locations_type = empty_locations;
482
483 template<typename ParseState>
484 [[nodiscard]] static constexpr locations_type<ParseState>
485 make_locations( ) {
486 return { };
487 }
488
489 template<typename JsonClass, typename ParseState>
490 [[nodiscard]] static DAW_JSON_SIMD_CONSTEXPR char const *
491 scan_class( ParseState &parse_state, empty_locations &,
492 simd_class_structural_state &structural_state ) {
493 using result_t = json_result_t<JsonClass>;
494 parse_state.trim_left( );
495 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
496 ErrorReason::InvalidClassStart,
497 parse_state );
498 auto const old_class_pos = parse_state.get_class_position( );
499 auto const class_first = parse_state.data( );
500 parse_state.set_class_position( );
501 auto event = structural_state.next( class_first );
502 daw_json_assert_weak( event != nullptr and *event == '{',
503 ErrorReason::InvalidClassStart,
504 parse_state );
505 event = structural_state.next( event + 1 );
506 if constexpr( all_json_members_must_exist_v<result_t, ParseState> ) {
507 daw_json_assert_weak( event != nullptr and *event == '}',
508 ErrorReason::UnknownMember,
509 parse_state );
510 } else {
511 auto object_depth = std::size_t{ 1 };
512 auto array_depth = std::size_t{ 0 };
513 auto found_end = false;
514 while( event != nullptr and not found_end ) {
515 switch( *event ) {
516 case '{':
517 ++object_depth;
518 break;
519 case '}':
520 if( object_depth == 1U and array_depth == 0U ) {
521 found_end = true;
522 break;
523 }
524 daw_json_assert_weak( object_depth > 1U,
525 ErrorReason::InvalidBracketing,
526 parse_state );
527 --object_depth;
528 break;
529 case '[':
530 ++array_depth;
531 break;
532 case ']':
533 daw_json_assert_weak( array_depth > 0U,
534 ErrorReason::InvalidBracketing,
535 parse_state );
536 --array_depth;
537 break;
538 default:
539 break;
540 }
541 if( not found_end ) {
542 event = structural_state.next( event + 1 );
543 }
544 }
545 daw_json_assert_weak( event != nullptr,
546 ErrorReason::UnexpectedEndOfData,
547 parse_state );
548 }
549 auto const class_end = event + 1;
550 parse_state.first = class_end;
551 parse_state.trim_left_checked( );
552 parse_state.set_class_position( old_class_pos );
553 return class_end;
554 }
555
556 template<typename JsonClass, typename ParseState>
557 [[nodiscard]] static constexpr json_result_t<JsonClass>
558 construct_class( ParseState &parse_state, empty_locations const & ) {
559 using result_t = json_result_t<JsonClass>;
560 using constructor_t = json_constructor_t<JsonClass>;
561 if constexpr( should_construct_explicitly_v<constructor_t,
562 result_t,
563 ParseState> ) {
564 return result_t{ };
565 } else {
566 return construct_value_tp<result_t, constructor_t>( parse_state,
567 fwd_pack{ } );
568 }
569 }
570 };
571
572 template<typename Locations>
573 struct simd_class_value_state {
574 char const *first = nullptr;
575 char const *last = nullptr;
576 Locations locations;
577 };
578
579 template<typename JsonMember, typename CharT, auto... PolicyFlags>
580 class json_simd_block_iterator_class {
581 static_assert( JsonMember::underlying_json_type ==
582 JsonBaseParseTypes::Class );
583 static_assert(
584 std::is_same_v<CharT, char>,
585 "SIMD class iteration currently supports char input only" );
586
587 using ParseState = TryDefaultParsePolicy<BasicParsePolicy<
588 options::details::make_parse_flags<PolicyFlags...>( ).value>>;
589 using parser_type =
590 simd_class_parser<typename JsonMember::json_member_list>;
591 using locations_type =
592 typename parser_type::template locations_type<ParseState>;
593 using value_state_type = simd_class_value_state<locations_type>;
594
595 public:
596 using json_member = JsonMember;
597 using value_type = typename json_member::parse_to_t;
598 using reference = value_type;
599 using difference_type = std::ptrdiff_t;
600 using iterator_category = std::input_iterator_tag;
601
602 private:
603 char const *m_first = nullptr;
604 char const *m_last = nullptr;
605 bool m_previous_value = false;
606 simd_class_structural_state m_structural_state{ };
607 value_state_type m_current{
608 nullptr,
609 nullptr,
610 parser_type::template make_locations<ParseState>( ) };
611
612 constexpr void move_to_next_value( ) {
613 m_current.first = nullptr;
614 m_current.last = nullptr;
615 if( m_first == nullptr or m_first == m_last ) {
616 return;
617 }
618
619 auto parse_state = ParseState( m_first, m_last );
620 parse_state.trim_left( );
621 if( parse_state.empty( ) ) {
622 m_first = m_last;
623 return;
624 }
625
626 if( m_previous_value ) {
627 if( parse_state.front( ) == ']' ) {
628 parse_state.remove_prefix( );
629 m_first = m_last;
630 return;
631 }
632 daw_json_assert_weak( parse_state.front( ) == ',',
633 ErrorReason::InvalidEndOfValue,
634 parse_state );
635 parse_state.remove_prefix( );
636 parse_state.trim_left( );
637 daw_json_assert_weak( not parse_state.empty( ) and
638 parse_state.front( ) != ']',
639 ErrorReason::TrailingComma,
640 parse_state );
641 } else if( parse_state.front( ) == ']' ) {
642 parse_state.remove_prefix( );
643 m_first = m_last;
644 return;
645 }
646
647 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
648 ErrorReason::InvalidClassStart,
649 parse_state );
650 m_current.first = parse_state.data( );
651 m_current.locations =
652 parser_type::template make_locations<ParseState>( );
653 m_current.last = parser_type::template scan_class<JsonMember>(
654 parse_state, m_current.locations, m_structural_state );
655 m_first = parse_state.data( );
656 m_previous_value = true;
657 }
658
659 public:
660 constexpr json_simd_block_iterator_class( ) = default;
661
662 explicit constexpr json_simd_block_iterator_class(
663 std::string_view document )
664 : m_first( document.data( ) )
665 , m_last( std::next( document.data( ), static_cast<std::ptrdiff_t>(
666 document.size( ) ) ) ) {
667 if( m_first != m_last ) {
668 auto parse_state = ParseState( m_first, m_last );
669 parse_state.trim_left( );
670 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
671 ErrorReason::InvalidArrayStart,
672 parse_state );
673 parse_state.remove_prefix( );
674 m_first = parse_state.data( );
675 m_structural_state.reset( m_first, m_last );
676 }
677 move_to_next_value( );
678 }
679
680 explicit constexpr json_simd_block_iterator_class(
681 std::string_view document, daw::string_view start_path )
682 : json_simd_block_iterator_class(
683 find_array_range<ParseState>( document, start_path ) ) {}
684
685 [[nodiscard]] constexpr reference operator*( ) const {
686 auto parse_state = ParseState( m_current.first, m_current.last );
687 parse_state.first = m_current.last;
688 return parser_type::template construct_class<json_member>(
689 parse_state, m_current.locations );
690 }
691
692 constexpr json_simd_block_iterator_class &operator++( ) {
693 move_to_next_value( );
694 return *this;
695 }
696
697 constexpr void operator++( int ) {
698 (void)operator++( );
699 }
700
701 [[nodiscard]] constexpr explicit operator bool( ) const noexcept {
702 return m_current.first != nullptr;
703 }
704
705 [[nodiscard]] constexpr json_simd_block_iterator_class begin( ) const {
706 return *this;
707 }
708
709 [[nodiscard]] constexpr json_simd_block_iterator_class static end( ) noexcept {
710 return { };
711 }
712
713 friend constexpr bool
714 operator==( json_simd_block_iterator_class const &lhs,
715 json_simd_block_iterator_class const &rhs ) noexcept {
716 auto const lhs_at_end = not lhs;
717 auto const rhs_at_end = not rhs;
718 if( lhs_at_end or rhs_at_end ) {
719 return lhs_at_end == rhs_at_end;
720 }
721 return lhs.m_current.first == rhs.m_current.first;
722 }
723
724 friend constexpr bool
725 operator!=( json_simd_block_iterator_class const &lhs,
726 json_simd_block_iterator_class const &rhs ) noexcept {
727 return not( lhs == rhs );
728 }
729 };
730 } // namespace json_details::simd_details
731 } // namespace DAW_JSON_VER
732} // namespace daw::json
733
734#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
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20