53 namespace json_details {
54 template<options::FPOutputFormat fp_output_format,
55 unsigned Precision = daw::max_value<unsigned>,
typename Real,
56 typename WriteableType>
57 constexpr WriteableType to_chars( Real
const &value,
58 WriteableType out_it );
61 namespace json_details::to_strings {
66 [[nodiscard]]
static constexpr auto to_string( std::optional<T>
const &v )
68 if( not has_value( v ) ) {
78 namespace json_details {
80 has_from_string_v, from_string( std::declval<daw::tag_t<T>>( ),
81 std::declval<std::string_view>( ) ) );
84 has_ostream_op_v,
operator<<( std::declval<std::stringstream &>( ),
85 std::declval<T const &>( ) ) );
88 has_istream_op_v,
operator>>( std::declval<std::stringstream &>( ),
89 std::declval<T const &>( ) ) );
103 std::stringstream ss{ };
105 return std::move( ss ).str( );
111 if constexpr( json_details::is_string_view_like_v<U> ) {
112 return std::string_view( std::data( value ), std::size( value ) );
113 }
else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
114 using json_details::to_strings::to_string;
116 }
else if constexpr( json_details::has_ostream_op_v<U> ) {
117 return use_stream( value );
118 }
else if constexpr( std::is_convertible_v<U, std::string_view> ) {
119 return static_cast<std::string_view
>( value );
120 }
else if constexpr( std::is_convertible_v<U, std::string> ) {
121 return static_cast<std::string
>( value );
122 }
else if constexpr( daw::is_arithmetic_v<U> ) {
124 }
else if constexpr( std::is_enum_v<U> ) {
125 return to_string(
static_cast<std::underlying_type_t<U>
>( value ) );
126 }
else if constexpr( concepts::is_nullable_value_v<U> ) {
127 using value_type = concepts::nullable_value_type_t<U>;
128 if constexpr( json_details::is_string_view_like_v<value_type> ) {
129 if constexpr( std::is_reference_v<DAW_TYPEOF(
130 concepts::nullable_value_read( value ) )> ) {
131 if( concepts::nullable_value_has_value( value ) ) {
132 return daw::string_view(
133 concepts::nullable_value_read( value ) );
135 return daw::string_view(
"null" );
137 if( concepts::nullable_value_has_value( value ) ) {
138 auto const &v = concepts::nullable_value_read( value );
139 return std::string( std::data( v ), std::size( v ) );
141 return std::string(
"null", 4 );
143 }
else if constexpr( json_details::to_strings::has_to_string_v<
145 if( concepts::nullable_value_has_value( value ) ) {
146 using json_details::to_strings::to_string;
147 return to_string( concepts::nullable_value_read( value ) );
149 using result_t = DAW_TYPEOF(
150 to_string( concepts::nullable_value_read( value ) ) );
151 return result_t{
"null" };
153 }
else if constexpr( std::is_convertible_v<value_type,
154 std::string_view> ) {
155 if( concepts::nullable_value_has_value( value ) ) {
156 return static_cast<std::string_view
>(
157 concepts::nullable_value_read( value ) );
159 return std::string_view{
"null" };
160 }
else if constexpr( std::is_convertible_v<value_type,
162 if( concepts::nullable_value_has_value( value ) ) {
163 return static_cast<std::string
>(
164 concepts::nullable_value_read( value ) );
166 return std::string(
"null" );
168 if( concepts::nullable_value_has_value( value ) ) {
169 return use_stream( concepts::nullable_value_has_value( value ) );
171 return std::string(
"null" );
178 namespace from_json_conv_details {
180 [[nodiscard]]
static auto use_stream( std::string_view sv ) {
181 std::stringstream ss{ };
193 if constexpr( std::is_same_v<T, std::string_view> or
194 std::is_same_v<T, std::optional<std::string_view>> ) {
196 }
else if constexpr( json_details::has_from_string_v<T> ) {
197 return from_string( daw::tag<T>, sv );
198 }
else if constexpr( std::is_convertible_v<std::string_view, T> ) {
199 return static_cast<T
>( sv );
200 }
else if constexpr( std::is_convertible_v<std::string, T> ) {
201 return static_cast<T
>(
static_cast<std::string
>( sv ) );
203 static_assert( json_details::has_istream_op_v<T>,
204 "Unsupported type in default to converter. Must "
205 "supply a custom one" );
206 static_assert( std::is_default_constructible_v<T>,
207 "Unsupported type in default to converter. Must "
208 "supply a custom one" );
209 return from_json_conv_details::use_stream<T>( sv );
214 namespace json_details {
216 template<
typename Char>
217 static constexpr char to_nibble_char( Char c ) {
218 auto const u =
static_cast<unsigned>(
static_cast<unsigned char>( c ) );
221 return static_cast<char>( u +
static_cast<unsigned char>(
'0' ) );
223 return static_cast<char>( ( u - 10U ) +
224 static_cast<unsigned char>(
'A' ) );
228 template<
typename WritableType>
229 static constexpr WritableType output_hex( std::uint16_t c,
231 char const nibbles[] = {
'\\',
233 to_nibble_char( ( c >> 12U ) & 0xFU ),
234 to_nibble_char( ( c >> 8U ) & 0xFU ),
235 to_nibble_char( ( c >> 4U ) & 0xFU ),
236 to_nibble_char( c & 0xFU ),
243 template<
typename WritableType>
244 static constexpr void utf32_to_utf8( std::uint32_t cp,
247 it.put(
static_cast<char>( cp ) );
252 static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
253 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
258 if( cp <= 0xFFFFU ) {
260 static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
261 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
262 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
267 if( cp <= 0x10FFFFU ) {
269 static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
270 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
271 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
272 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
282 template<
bool RestrictHigh,
typename WriteableType>
283 [[nodiscard]]
static constexpr WriteableType
310 json_details::output_hex(
static_cast<std::uint16_t
>( cp ), it );
313 if constexpr( RestrictHigh ) {
314 if( cp >= 0x80U and cp <= 0xFFFFU ) {
315 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
320 it = json_details::output_hex(
321 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
322 it = json_details::output_hex(
323 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ), it );
327 json_details::utf32_to_utf8( cp, it );
333#if defined( DAW_JSON_HAS_SERIALIZE_STRING_SIMD )
339 template<
typename WritableType>
340 [[nodiscard]] DAW_ATTRIB_NOINLINE
static WritableType
341 copy_escaped_string_simd( WritableType it,
char const *first,
342 char const *
const last ) {
343 using it_t = utf8::unchecked::iterator<char const *>;
344 if( first >= last ) {
348 json_details::serialize_string_simd::escape_scanner( first, last );
349 while( first < last ) {
350 auto const hit = scanner.next( first );
352 it.write( daw::string_view(
353 first,
static_cast<std::size_t
>( hit - first ) ) );
358 auto const c =
static_cast<unsigned char>( *hit );
360 it = escape_codepoint_to_iterator<false>( it, c );
367 constexpr auto block_mask =
static_cast<std::uintptr_t
>(
368 json_details::serialize_string_simd::block_size - 1U );
369 auto const block_end_addr =
370 (
reinterpret_cast<std::uintptr_t
>( hit ) | block_mask ) + 1U;
371 auto const block_end =
372 block_end_addr < reinterpret_cast<std::uintptr_t>( last )
374 ( block_end_addr -
reinterpret_cast<std::uintptr_t
>( hit ) )
376 auto cp_first = it_t( hit );
377 while( cp_first.base( ) < block_end ) {
378 auto const cp_start = cp_first;
379 auto const cp = *cp_first++;
380 if( cp_start == cp_first ) {
382 if constexpr( WritableType::restricted_string_output ==
383 options::RestrictedStringOutput::
387 cp_first = it_t( std::next( cp_first.base( ) ) );
390 it = escape_codepoint_to_iterator<false>( it, cp );
392 first = cp_first.base( );
399 bool do_escape =
false,
400 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
401 bool use_scanned_write =
false,
typename WritableType,
402 typename Container DAW_ENABLEIF(
403 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )>
405 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )
406 [[nodiscard]]
static constexpr WritableType
408 using restrict_high = std::bool_constant<
409 EightBitMode != options::EightBitModes::AllowFull or
410 ( WritableType::restricted_string_output ==
411 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
412 if constexpr( do_escape ) {
413 if constexpr( use_scanned_write and
414 json_details::is_string_view_like_v<Container> ) {
415 auto const *
const data = std::data(
container );
416 auto const size = std::size(
container );
417#if defined( DAW_JSON_HAS_SERIALIZE_STRING_SIMD )
419 if constexpr( not restrict_high::value and
420 std::is_same_v<daw::remove_cvref_t<
decltype( *data )>,
423 if( not DAW_IS_CONSTANT_EVALUATED_COMPAT( ) and
424 size >= json_details::serialize_string_simd::block_size ) {
425 return copy_escaped_string_simd( it, data, data + size );
429 bool is_ascii =
true;
430 for( std::size_t n = 0; n < size; ++n ) {
431 if(
static_cast<unsigned char>( data[n] ) >= 0x80U ) {
437 auto const *first = data;
438 auto const *pos = data;
439 auto const *
const last = data + size;
440 while( pos != last ) {
441 auto const c =
static_cast<unsigned char>( *pos );
442 if( c !=
'"' and c !=
'\\' and c >= 0x20U ) {
447 it.write( daw::string_view(
448 first,
static_cast<std::size_t
>( pos - first ) ) );
473 it = json_details::output_hex(
474 static_cast<std::uint16_t
>( c ), it );
480 if( first != last ) {
481 it.write( daw::string_view(
482 first,
static_cast<std::size_t
>( last - first ) ) );
487 using iter = DAW_TYPEOF( std::begin(
container ) );
488 using it_t = utf8::unchecked::iterator<iter>;
490 auto first = it_t( std::begin(
container ) );
491 auto const last = it_t( std::end(
container ) );
492 while( first != last ) {
493 auto const last_it = first;
494 auto const cp = *first++;
495 if( last_it == first ) {
497 if constexpr( WritableType::restricted_string_output ==
498 options::RestrictedStringOutput::
502 first = it_t( std::next( first.base( ) ) );
505 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
508 if constexpr( json_details::is_string_view_like_v<Container> ) {
509 if constexpr( restrict_high::value ) {
510 for(
auto c : container ) {
512 static_cast<unsigned char>( c ) <= 0x7FU ),
513 ErrorReason::InvalidStringHighASCII );
516 it.write( daw::string_view( std::data( container ),
517 std::size( container ) ) );
519 for(
auto c : container ) {
520 if constexpr( restrict_high::value ) {
522 static_cast<unsigned char>( c ) <= 0x7FU ),
523 ErrorReason::InvalidStringHighASCII );
533 bool do_escape =
false,
534 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
535 typename WriteableType>
536 [[nodiscard]]
static constexpr WriteableType
538 if( ptr ==
nullptr ) {
541 using restrict_high = std::bool_constant<
542 EightBitMode != options::EightBitModes::AllowFull or
543 ( WriteableType::restricted_string_output ==
544 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
546 if constexpr( do_escape ) {
547 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
548 while( *chr_it.base( ) !=
'\0' ) {
549 auto const cp = *chr_it++;
550 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
552 }
else if constexpr( restrict_high::value ) {
553 auto const *
const first = ptr;
554 while( *ptr !=
'\0' ) {
556 static_cast<unsigned char>( *ptr ) <= 0x7FU ),
557 ErrorReason::InvalidStringHighASCII );
560 it.write( daw::string_view(
561 first,
static_cast<std::size_t
>( ptr - first ) ) );
569 bool do_escape =
false,
570 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
572 [[nodiscard]]
static constexpr WriteableType
575 return copy_to_iterator<do_escape, EightBitMode>( it,
"null" );
577 return copy_to_iterator<do_escape, EightBitMode>(
583 namespace json_details {
584 template<
typename Writer,
typename Name>
585 [[nodiscard]] DAW_ATTRIB_INLINE
constexpr Writer
586 encode_name( Writer it, Name &&name ) {
587 if constexpr( Writer::allow_escaped_names ) {
588 return utils::copy_to_iterator<true>( it, DAW_FWD( name ) );
595 namespace enc_name_impl {
598 template<
bool do_escape,
typename Name>
599 [[nodiscard]] DAW_ATTRIB_INLINE
constexpr std::size_t
600 encode_name_to_buffer(
char *buf, Name
const &name ) {
603 (void)utils::copy_to_iterator<do_escape>(
604 serialization_policy<char *>( ptr ), name );
605 return static_cast<std::size_t
>( ptr - buf );
610 template<
typename JsonMember>
611 [[nodiscard]] DAW_ATTRIB_INLINE
constexpr auto encode_member_name( ) {
613 constexpr std::size_t len = [] {
615 auto r = std::array<char, JsonMember::name.size( ) * 6U>{ };
616 return encode_name_to_buffer<true>( r.data( ), JsonMember::name );
621 [[nodiscard]]
constexpr static std::size_t size( ) {
624 [[nodiscard]]
constexpr char const *data( )
const {
627 [[nodiscard]]
constexpr char const *c_str( )
const {
630 [[nodiscard]]
explicit constexpr
631 operator daw::string_view( )
const {
632 return daw::string_view( data( ), size( ), zero_terminated );
636 (void)encode_name_to_buffer<true>( result.buff, JsonMember::name );
640 template<JSONNAMETYPE Name>
642 static constexpr daw::string_view name = Name;
645 template<JSONNAMETYPE Name>
646 [[nodiscard]] DAW_ATTRIB_INLINE
constexpr auto encode_json_name( ) {
647 return encode_member_name<fake_member<Name>>( );
650 template<
typename JsonMember>
651 inline constexpr auto encode_member_name_v =
652 enc_name_impl::encode_member_name<JsonMember>( );
654 template<JSONNAMETYPE Name>
655 inline constexpr auto encode_json_name_v =
656 enc_name_impl::encode_json_name<Name>( );
658 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
660 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
661 to_daw_json_string( WriteableType it, parse_to_t
const &value );
663 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
664 [[nodiscard]]
static constexpr WriteableType
665 to_json_string_bool( WriteableType it, parse_to_t
const &value ) {
667 if constexpr( JsonMember::literal_as_string ==
668 options::LiteralAsStringOpt::Always ) {
670 it.write(
"\"true\"" );
672 it.write(
"\"false\"" );
684 template<std::size_t idx,
typename JsonMembers,
typename WriteableType,
686 static constexpr void to_variant_string( WriteableType &it,
687 parse_to_t
const &value ) {
688 if constexpr( idx < std::variant_size_v<parse_to_t> ) {
689 if( value.index( ) != idx ) {
690 to_variant_string<idx + 1, JsonMembers>( it, value );
693 using element_t =
typename JsonMembers::json_elements;
695 typename pack_element<idx, typename element_t::element_map_t>::type;
696 it = to_daw_json_string<JsonMember, JsonMember::expected_type>(
697 it, daw::get_nt<idx>( value ) );
701 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
702 [[nodiscard]]
static constexpr WriteableType
703 to_json_string_variant( WriteableType it, parse_to_t
const &value ) {
705 assert( value.index( ) >= 0 );
706 to_variant_string<0, JsonMember>( it, value );
710 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
711 [[nodiscard]]
static constexpr WriteableType
712 to_json_string_variant_tagged( WriteableType it,
713 parse_to_t
const &value ) {
715 to_variant_string<0, JsonMember>( it, value );
719 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
720 [[nodiscard]]
static constexpr WriteableType
721 to_json_string_variant_intrusive( WriteableType it,
722 parse_to_t
const &value ) {
724 to_variant_string<0, JsonMember>( it, value );
728 template<
typename ,
typename =
void>
729 inline constexpr bool has_null_checker_v =
false;
731 template<
typename JsonMember>
732 inline constexpr bool has_null_checker_v<
733 JsonMember, std::void_t<typename JsonMember::is_null_checker>> =
734 not std::is_same_v<use_default, typename JsonMember::is_null_checker>;
736 template<
typename JsonMember,
typename WriteableType,
typename Optional>
737 [[nodiscard]]
static constexpr WriteableType
738 to_json_string_null( WriteableType it, Optional
const &value ) {
740 if constexpr( has_null_checker_v<JsonMember> ) {
742 using is_null_checker_t =
typename JsonMember::is_null_checker;
743 if( is_null_checker_t{ }( value ) ) {
747 }
else if constexpr( has_op_bool_v<Optional> ) {
748 if( not
static_cast<bool>( value ) ) {
756 if( not concepts::nullable_value_has_value( value ) ) {
761 using member_type =
typename JsonMember::member_type;
762 return to_daw_json_string<member_type, member_type::expected_type>(
764 if constexpr( is_char_pointer_v<Optional> and
765 member_type::underlying_json_type ==
766 JsonBaseParseTypes::String ) {
768 return daw::string_view( value );
769 }
else if constexpr( concepts::is_nullable_value_v<Optional> ) {
770 return concepts::nullable_value_traits<Optional>::read( value );
771 }
else if constexpr( json_details::has_op_star_v<Optional> ) {
781 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
782 [[nodiscard]]
static constexpr WriteableType
783 to_json_string_real( WriteableType it, parse_to_t
const &value ) {
786 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
787 "value must be convertible to specified type in class contract" );
789 if constexpr( std::is_floating_point_v<json_result_t<JsonMember>> ) {
790 if( daw::cxmath::is_nan( value ) ) {
791 if constexpr( JsonMember::literal_as_string ==
792 options::LiteralAsStringOpt::Never or
793 JsonMember::allow_number_errors ==
794 options::JsonNumberErrors::None or
795 JsonMember::allow_number_errors ==
796 options::JsonNumberErrors::AllowInf ) {
799 it.write(
"\"NaN\"" );
802 }
else if( daw::cxmath::is_inf( value ) ) {
803 if constexpr( JsonMember::literal_as_string ==
804 options::LiteralAsStringOpt::Never or
805 JsonMember::allow_number_errors ==
806 options::JsonNumberErrors::None or
807 JsonMember::allow_number_errors ==
808 options::JsonNumberErrors::AllowNaN ) {
812 it.write(
"\"-Infinity\"" );
814 it.write(
"\"Infinity\"" );
821 if constexpr( JsonMember::literal_as_string ==
822 options::LiteralAsStringOpt::Always ) {
825 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
826 static_assert(
sizeof( parse_to_t ) <=
sizeof(
double ) );
827 if constexpr( has_fp_precision_v<JsonMember> ) {
828 it = to_chars<JsonMember::fp_output_format, JsonMember::precision>(
831 it = to_chars<JsonMember::fp_output_format>( value, it );
834 using std::to_string;
835 using to_strings::to_string;
836 it = utils::copy_to_iterator( it,
to_string( value ) );
838 if constexpr( JsonMember::literal_as_string ==
839 options::LiteralAsStringOpt::Always ) {
846 using base_int_type_impl = std::underlying_type<T>;
849 using base_int_type_t =
850 typename daw::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
851 daw::traits::identity<T>>::type;
853 DAW_ATTRIB_INLINE DAW_CONSTEVAL std::array<char[2], 100>
855 auto result = std::array<char[2], 100>{ };
856 for( std::size_t n = 0;
n < 100; ++
n ) {
858 static_cast<char>( (
n % 10 ) +
static_cast<unsigned char>(
'0' ) );
860 static_cast<char>( (
n / 10 ) +
static_cast<unsigned char>(
'0' ) );
864 inline constexpr auto digits100 = make_digits100( );
867 static constexpr void reverse( T *first, T *last ) {
870 DAW_ASSUME( first and last );
871 DAW_ASSUME( first <= last );
872 auto rpos = last - first;
874 while( lpos < rpos ) {
876 auto tmp = std::move( first[lpos] );
877 first[lpos] = std::move( first[rpos] );
878 first[rpos] = std::move( tmp );
883 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
884 [[nodiscard]]
static constexpr WriteableType
885 to_json_string_signed( WriteableType it, parse_to_t
const &value ) {
888 daw::is_explicitly_convertible_v<parse_to_t,
889 json_base_type_t<JsonMember>>,
890 "value must be convertible to specified type in class contract" );
892 using std::to_string;
893 using to_strings::to_string;
894 using under_type = base_int_type_t<parse_to_t>;
896 if constexpr( std::is_enum_v<parse_to_t> or
897 daw::is_integral_v<parse_to_t> ) {
898 auto v =
static_cast<under_type
>( value );
900 char buff[daw::digits10<under_type> + 10]{ };
901 char *num_start = buff;
903 if constexpr( JsonMember::literal_as_string ==
904 options::LiteralAsStringOpt::Always ) {
914 auto const tmp = -
static_cast<std::size_t
>( v % 10 );
916 *ptr++ = digits100[tmp][0];
918 if constexpr( JsonMember::literal_as_string ==
919 options::LiteralAsStringOpt::Always ) {
922 it.copy_buffer( buff, ptr );
931 auto const tmp =
static_cast<std::size_t
>( v % 100 );
933 ptr[0] = digits100[tmp][0];
934 ptr[1] = digits100[tmp][1];
938 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
941 reverse( num_start, ptr );
942 if constexpr( JsonMember::literal_as_string ==
943 options::LiteralAsStringOpt::Always ) {
946 it.copy_buffer( buff, ptr );
949 if constexpr( JsonMember::literal_as_string ==
950 options::LiteralAsStringOpt::Always ) {
954 it = utils::copy_to_iterator( it,
to_string( value ) );
955 if constexpr( JsonMember::literal_as_string ==
956 options::LiteralAsStringOpt::Always ) {
963 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
964 [[nodiscard]]
static constexpr WriteableType
965 to_json_string_unsigned( WriteableType it, parse_to_t
const &value ) {
968 daw::is_explicitly_convertible_v<parse_to_t,
969 json_result_t<JsonMember>>,
970 "value must be convertible to specified type in class contract" );
972 using std::to_string;
973 using to_strings::to_string;
974 using under_type = base_int_type_t<parse_to_t>;
975 if constexpr( JsonMember::literal_as_string ==
976 options::LiteralAsStringOpt::Always ) {
979 if constexpr( std::is_same_v<under_type, bool> ) {
980 if(
static_cast<bool>( value ) ) {
985 }
else if constexpr( std::is_enum_v<parse_to_t> or
986 daw::is_integral_v<parse_to_t> ) {
987 auto v =
static_cast<under_type
>( value );
989 if( DAW_UNLIKELY( v == 0 ) ) {
993 char buff[daw::digits10<under_type> + 10U]{ };
996 auto const tmp =
static_cast<std::size_t
>( v % 100U );
998 ptr[0] = digits100[tmp][0];
999 ptr[1] = digits100[tmp][1];
1003 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
1005 reverse( buff, ptr );
1006 it.copy_buffer( buff, ptr );
1010 it = utils::copy_to_iterator( it,
to_string( value ) );
1012 if constexpr( JsonMember::literal_as_string ==
1013 options::LiteralAsStringOpt::Always ) {
1021 namespace utils_details {
1022 template<
typename Integer>
1024 using parse_to_t = Integer;
1025 using base_type = parse_to_t;
1026 static constexpr options::LiteralAsStringOpt literal_as_string =
1027 options::LiteralAsStringOpt::Never;
1031 template<
typename Integer,
typename WriteableType>
1033 Integer
const &value ) {
1034 static_assert( daw::is_integral_v<Integer> );
1036 if constexpr( daw::is_unsigned_v<Integer> ) {
1037 return json_details::to_json_string_unsigned<
1038 utils_details::number<Integer>>( it, value );
1040 return json_details::to_json_string_signed<
1041 utils_details::number<Integer>>( it, value );
1046 namespace json_details {
1048 std::size( std::declval<T const &>( ) ) );
1050 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1051 [[nodiscard]]
static constexpr WriteableType
1052 to_json_string_string_raw( WriteableType it, parse_to_t
const &value ) {
1055 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1056 "Value must be convertible to specialized type in "
1057 "json_data_contract" );
1059 it.reserve( std::size( value ) + 2U );
1061 if( std::size( value ) > 0U ) {
1062 it = utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
1069 template<
typename JsonMember,
typename =
void>
1070 inline constexpr options::EscapeValidUTF8 escape_output_v =
1071 options::EscapeValidUTF8::Validate;
1073 template<
typename JsonMember>
1074 inline constexpr options::EscapeValidUTF8 escape_output_v<
1075 JsonMember, std::void_t<
decltype( JsonMember::escape_output )>> =
1076 JsonMember::escape_output;
1078 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1079 [[nodiscard]]
static constexpr WriteableType
1080 to_json_string_string_escaped( WriteableType it,
1081 parse_to_t
const &value ) {
1082 if constexpr( is_char_array_v<parse_to_t> ) {
1084 return to_json_string_string_escaped<JsonMember>(
1085 it, daw::string_view( value, std::extent_v<parse_to_t> - 1U ) );
1086 }
else if constexpr( std::is_same_v<parse_to_t, char> ) {
1087 return to_json_string_string_escaped<JsonMember>(
1088 it, daw::string_view( &value, 1U ) );
1090 if constexpr( has_std_size_v<parse_to_t> ) {
1092 it.reserve( std::size( value ) + 2U );
1095 it = utils::copy_to_iterator<escape_output_v<JsonMember> !=
1096 options::EscapeValidUTF8::AssumeValid,
1097 JsonMember::eight_bit_mode,
1104 template<
typename T>
1105 [[nodiscard]]
static constexpr bool is_null( std::optional<T>
const &v ) {
1106 return not
static_cast<bool>( v );
1109 template<
typename T>
1110 [[nodiscard]]
static constexpr bool is_null( T
const & ) {
1114 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1115 [[nodiscard]]
static constexpr WriteableType
1116 to_json_string_date( WriteableType it, parse_to_t
const &value ) {
1119 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1120 "value must be convertible to specified type in class contract" );
1122 using json_details::is_null;
1124 if( is_null( value ) ) {
1129 datetime::ymdhms civil = datetime::time_point_to_civil( value );
1130 it = utils::integer_to_string( it, civil.year );
1132 if( civil.month < 10 ) {
1135 it = utils::integer_to_string( it, civil.month );
1137 if( civil.day < 10 ) {
1140 it = utils::integer_to_string( it, civil.day );
1142 if( civil.hour < 10 ) {
1145 it = utils::integer_to_string( it, civil.hour );
1147 if( civil.minute < 10 ) {
1150 it = utils::integer_to_string( it, civil.minute );
1152 if( civil.second < 10 ) {
1155 it = utils::integer_to_string( it, civil.second );
1156 if( civil.attosecond > 0 ) {
1157 auto fractional_digits = std::size_t{ 18 };
1158 while( civil.attosecond % 10 == 0 ) {
1159 civil.attosecond /= 10;
1160 --fractional_digits;
1163 auto const digit_count =
static_cast<std::size_t
>(
1164 daw::cxmath::count_digits( civil.attosecond ) );
1165 while( digit_count < fractional_digits ) {
1167 --fractional_digits;
1169 it = utils::integer_to_string( it, civil.attosecond );
1175 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1176 [[nodiscard]]
static constexpr WriteableType
1177 to_json_string_unknown( WriteableType it, parse_to_t
const &value ) {
1179 return utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
1183 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1184 [[nodiscard]]
static constexpr WriteableType
1185 to_json_string_class( WriteableType it, parse_to_t
const &value ) {
1188 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>> or
1189 std::is_same_v<parse_to_t,
1190 json_result_t<JsonMember>>,
1193 "value must be convertible to specified type in class contract" );
1195 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
1196 return json_data_contract_trait_t<typename JsonMember::wrapped_type>::
1200 typename JsonMember::wrapped_type>::to_json_data( value ),
1202 }
else if constexpr( is_json_map_alias_v<parse_to_t> ) {
1203 return json_data_contract_trait_t<parse_to_t>::serialize(
1205 }
else if constexpr( std::is_empty_v<parse_to_t> and
1206 std::is_default_constructible_v<parse_to_t> and
1207 not has_json_data_contract_trait_v<parse_to_t> ) {
1211 static_assert( is_submember_tagged_variant_v<parse_to_t>,
1212 "Could not find appropriate mapping or to_json_data "
1213 "member of json_data_contract" );
1214 return json_data_contract_trait_t<parse_to_t>::serialize( it, value );
1218 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1219 [[nodiscard]]
static constexpr WriteableType
1220 to_json_string_reflected_class( WriteableType it,
1221 parse_to_t
const &value ) {
1223 return JsonMember::serialize( it, value );
1226 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1227 [[nodiscard]]
static constexpr WriteableType
1228 to_json_string_custom( WriteableType it, parse_to_t
const &value ) {
1231 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1232 "value must be convertible to specified type in class contract" );
1234 if constexpr( JsonMember::custom_json_type ==
1235 options::JsonCustomTypes::String ) {
1239 if constexpr( daw::is_callable_r_v<WriteableType,
1240 typename JsonMember::to_converter_t,
1243 it =
typename JsonMember::to_converter_t{ }( it, value );
1245 it = utils::copy_to_iterator(
1246 it,
typename JsonMember::to_converter_t{ }( value ) );
1249 if constexpr( JsonMember::custom_json_type ==
1250 options::JsonCustomTypes::String ) {
1256 template<
typename JsonMember,
typename WriteableType,
1259 DAW_ATTRIB_INLINE
constexpr serialization_policy<WriteableType,
1260 SerializationOptions>
1261 to_daw_json_string_tuple(
1262 serialization_policy<WriteableType, SerializationOptions> it,
1263 parse_to_t
const &value, std::index_sequence<Is...> ) {
1265 auto const to_daw_json_string_help = [&](
auto Idx ) {
1266 using index = daw::remove_cvref_t<
decltype( Idx )>;
1267 using pack_element = tuple_elements_pack<parse_to_t>;
1268 using T = std::tuple_element_t<index::value,
1269 typename JsonMember::sub_member_list>;
1271 it = to_daw_json_string<T, T::expected_type>(
1272 it, pack_element::template get<index::value>( value ) );
1273 if constexpr( index::value + 1 <
sizeof...( Is ) ) {
1278 (void)to_daw_json_string_help;
1280 daw::empty_t
const expander[]{
1281 ( to_daw_json_string_help( daw::constant_v<Is> ),
1282 daw::empty_t{ } )...,
1289 template<
typename JsonMember,
typename WriteableType,
1291 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1292 SerializationOptions>
1293 to_json_string_tuple(
1294 serialization_policy<WriteableType, SerializationOptions> it,
1295 parse_to_t
const &value ) {
1297 using tuple_t = json_result_t<JsonMember>;
1299 using element_pack = tuple_elements_pack<
typename daw::conditional_t<
1300 is_tuple_v<tuple_t>,
1301 daw::traits::identity<tuple_t>,
1302 json_details::identity_parts<tp_from_struct_binding_result_t,
1303 parse_to_t>>::type>;
1306 std::is_convertible_v<parse_to_t, tuple_t>,
1307 "value must be convertible to specified type in class contract" );
1312 if constexpr( is_tuple_v<tuple_t> ) {
1313 it = to_daw_json_string_tuple<JsonMember>(
1314 it, value, std::make_index_sequence<element_pack::size>{ } );
1316 auto value2 = to_tuple_impl( DAW_FWD( value ) );
1318 using value2_t = tp_from_struct_binding_result_t<parse_to_t>;
1319 it = to_daw_json_string_tuple<json_base::json_tuple<value2_t>>(
1320 it, value2, std::make_index_sequence<element_pack::size>{ } );
1323 if constexpr( element_pack::size > 0 ) {
1324 if constexpr( element_pack::size > 0 and
1325 it.output_trailing_comma ==
1326 options::OutputTrailingComma::Yes ) {
1338 template<
typename JsonElement>
1339 inline constexpr std::size_t estimated_json_width_v = [] {
1340 using value_t = json_result_t<JsonElement>;
1341 constexpr auto type = JsonElement::expected_type;
1343 if constexpr( type == JsonParseTypes::Signed ) {
1345 return static_cast<std::size_t
>( daw::digits10<value_t> ) + 2U;
1346 }
else if constexpr( type == JsonParseTypes::Unsigned ) {
1347 return static_cast<std::size_t
>( daw::digits10<value_t> ) + 1U;
1348 }
else if constexpr( type == JsonParseTypes::Real ) {
1351 if constexpr( std::is_same_v<value_t, float> ) {
1352 return std::size_t{ 16 };
1353 }
else if constexpr( std::is_same_v<value_t, double> ) {
1354 return std::size_t{ 24 };
1356 return std::size_t{ 0 };
1358 }
else if constexpr( type == JsonParseTypes::Bool ) {
1359 return std::size_t{ 5 };
1360 }
else if constexpr( type == JsonParseTypes::Null ) {
1361 constexpr auto inner =
1362 estimated_json_width_v<typename JsonElement::member_type>;
1367 if constexpr( inner != 0 ) {
1368 return inner > 4U ? inner : std::size_t{ 4 };
1373 return std::size_t{ 0 };
1380 template<
typename JsonElement,
typename Container,
typename WriteableType>
1381 DAW_ATTRIB_INLINE
constexpr void
1382 reserve_array_output( WriteableType &it, Container
const &c ) {
1383 if constexpr( has_std_size_v<Container> ) {
1384 constexpr auto width = estimated_json_width_v<JsonElement>;
1385 if constexpr( width != 0 ) {
1387 it.reserve( std::size( c ) * ( width + 1U ) + 2U );
1388 }
else if constexpr( JsonElement::expected_type ==
1389 JsonParseTypes::StringRaw or
1390 JsonElement::expected_type ==
1391 JsonParseTypes::StringEscaped ) {
1393 daw::remove_cvref_t<
decltype( *std::begin( c ) )>;
1394 if constexpr( has_std_size_v<element_t> ) {
1396 auto total = std::size_t{ 2 };
1397 for(
auto const &e : c ) {
1398 total += std::size( e ) + 3U;
1400 it.reserve( total );
1407 is_view_like_v, ( (
void)( std::begin( std::declval<T &>( ) ) ),
1408 (
void)( std::end( std::declval<T &>( ) ) ),
1409 (
void)( std::declval<typename T::value_type>( ) ) ) );
1411 template<
typename JsonMember,
typename WriteableType,
1413 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1414 SerializationOptions>
1415 to_json_string_array(
1416 serialization_policy<WriteableType, SerializationOptions> it,
1417 parse_to_t
const &value ) {
1419 using array_t = json_result_t<JsonMember>;
1420 if constexpr( is_view_like_v<array_t> ) {
1422 std::is_convertible_v<parse_to_t, array_t>,
1423 "value must be convertible to specified type in class contract" );
1426 is_pointer_like_v<array_t>,
1427 "This is a special case for pointer like(T*, unique_ptr<T>, "
1428 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1429 "encode the size of the data with the pointer. Will take any "
1430 "Container like type, but std::span like types work too" );
1432 is_view_like_v<parse_to_t>,
1433 "This is a special case for pointer like(T*, unique_ptr<T>, "
1434 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1435 "encode the size of the data with the pointer. Will take any "
1436 "Container like type, but std::span like types work too" );
1439 reserve_array_output<typename JsonMember::json_element_t>( it, value );
1442 auto first = std::begin( value );
1443 auto last = std::end( value );
1444 bool const has_elements = first != last;
1445 while( first != last ) {
1447 it = to_daw_json_string<
typename JsonMember::json_element_t,
1448 JsonMember::json_element_t::expected_type>(
1451 if( first != last ) {
1456 if constexpr( it.output_trailing_comma ==
1457 options::OutputTrailingComma::Yes ) {
1458 if( has_elements ) {
1462 if( has_elements ) {
1469 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1470 [[nodiscard]]
static constexpr WriteableType
1471 to_json_string_sized_array( WriteableType it, parse_to_t
const &value ) {
1472 return to_json_string_array<JsonMember>( it, value );
1475 template<
typename Key,
typename Value>
1476 static constexpr Key
const &
1477 json_get_key( std::pair<Key, Value>
const &kv ) {
1481 template<
typename Key,
typename Value>
1482 static constexpr Value
const &
1483 json_get_value( std::pair<Key, Value>
const &kv ) {
1487 template<
typename JsonMember,
typename WriteableType,
1489 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1491 to_json_string_kv_array(
1492 serialization_policy<WriteableType, SerializeOptions> it,
1493 parse_to_t
const &value ) {
1496 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1497 "value must be convertible to specified type in class contract" );
1498 using key_t =
typename JsonMember::json_key_t;
1499 using value_t =
typename JsonMember::json_value_t;
1502 auto first = std::begin( value );
1503 auto last = std::end( value );
1504 bool const has_elements = first != last;
1505 while( first != last ) {
1511 it.write(
'"', encode_member_name_v<key_t>,
"\":", it.space );
1513 it = to_daw_json_string<key_t, key_t::expected_type>(
1514 it, json_get_key( *first ) );
1519 it.write(
'"', encode_member_name_v<value_t>,
"\":", it.space );
1521 it = to_daw_json_string<value_t, value_t::expected_type>(
1522 it, json_get_value( *first ) );
1525 if constexpr( it.output_trailing_comma ==
1526 options::OutputTrailingComma::Yes ) {
1527 if( has_elements ) {
1534 if( first != last ) {
1539 if constexpr( it.output_trailing_comma ==
1540 options::OutputTrailingComma::Yes ) {
1541 if( has_elements ) {
1545 if( has_elements ) {
1552 template<
typename JsonMember,
typename WriteableType,
1554 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1555 SerializationOptions>
1557 serialization_policy<WriteableType, SerializationOptions> it,
1558 parse_to_t
const &value ) {
1562 auto first = std::begin( value );
1563 auto last = std::end( value );
1564 bool const has_elements = first != last;
1565 while( first != last ) {
1566 auto const &v = *first;
1568 it = to_daw_json_string<
typename JsonMember::json_key_t,
1569 JsonMember::json_key_t::expected_type>(
1570 it, json_get_key( v ) );
1571 it.write(
':', it.space );
1572 it = to_daw_json_string<
typename JsonMember::json_element_t,
1573 JsonMember::json_element_t::expected_type>(
1574 it, json_get_value( v ) );
1576 if( first != last ) {
1581 if constexpr( it.output_trailing_comma ==
1582 options::OutputTrailingComma::Yes ) {
1583 if( has_elements ) {
1587 if( has_elements ) {
1594 template<
typename JsonMember,
typename WriteableType,
typename T>
1595 [[nodiscard]]
static constexpr WriteableType
1596 to_json_string_submember( WriteableType it, daw::string_view path,
1599 template<
typename JsonMember,
typename WriteableType,
typename T>
1600 [[nodiscard]]
static constexpr WriteableType
1601 to_json_string_submember_array( WriteableType it, daw::string_view path,
1603 auto const index = pop_json_path( path );
1608 index.current.size( ) == 1 and
1609 index.current.front( ) ==
'0',
1610 ErrorReason::OutputError );
1615 if( path.empty( ) ) {
1616 using member_type =
typename JsonMember::member_type;
1617 it = to_daw_json_string<member_type, member_type::expected_type>(
1620 it = to_json_string_submember<JsonMember>( it, path, value );
1623 if constexpr( it.output_trailing_comma ==
1624 options::OutputTrailingComma::Yes ) {
1632 template<
typename JsonMember,
typename WriteableType,
typename T>
1633 [[nodiscard]]
static constexpr WriteableType
1634 to_json_string_submember( WriteableType it, daw::string_view path,
1636 auto const path_item = pop_json_path( path );
1637 if( path_item.current.empty( ) ) {
1639 ErrorReason::OutputError );
1640 return to_json_string_submember_array<JsonMember>( it, path, value );
1647 auto name = path_item.current;
1649 while( not name.empty( ) ) {
1650 auto const segment = name.pop_front_until(
'\\', daw::nodiscard );
1651 it = encode_name( it, segment );
1652 if( name.empty( ) ) {
1655 name.remove_prefix( );
1657 it = encode_name( it, name.pop_front( 1 ) );
1659 it.write(
"\":", it.space );
1661 if( path_item.found_char ==
'[' ) {
1662 it = to_json_string_submember_array<JsonMember>( it, path, value );
1663 }
else if( path.empty( ) ) {
1664 using member_type =
typename JsonMember::member_type;
1665 it = to_daw_json_string<member_type, member_type::expected_type>(
1668 it = to_json_string_submember<JsonMember>( it, path, value );
1671 if constexpr( it.output_trailing_comma ==
1672 options::OutputTrailingComma::Yes ) {
1680 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
1681 typename parse_to_t>
1682 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
1683 to_daw_json_string( WriteableType it, parse_to_t
const &value ) {
1684 if constexpr( Tag == JsonParseTypes::Real ) {
1685 return to_json_string_real<JsonMember>( it, value );
1686 }
else if constexpr( Tag == JsonParseTypes::Signed ) {
1687 return to_json_string_signed<JsonMember>( it, value );
1688 }
else if constexpr( Tag == JsonParseTypes::Unsigned ) {
1689 return to_json_string_unsigned<JsonMember>( it, value );
1690 }
else if constexpr( Tag == JsonParseTypes::Null ) {
1691 return to_json_string_null<JsonMember>( it, value );
1692 }
else if constexpr( Tag == JsonParseTypes::Bool ) {
1693 return to_json_string_bool<JsonMember>( it, value );
1694 }
else if constexpr( Tag == JsonParseTypes::StringRaw ) {
1695 return to_json_string_string_raw<JsonMember>( it, value );
1696 }
else if constexpr( Tag == JsonParseTypes::StringEscaped or
1697 Tag == JsonParseTypes::StringInsitu ) {
1698 return to_json_string_string_escaped<JsonMember>( it, value );
1699 }
else if constexpr( Tag == JsonParseTypes::Date ) {
1700 return to_json_string_date<JsonMember>( it, value );
1701 }
else if constexpr( Tag == JsonParseTypes::Custom ) {
1702 return to_json_string_custom<JsonMember>( it, value );
1703 }
else if constexpr( Tag == JsonParseTypes::Class ) {
1704 return to_json_string_class<JsonMember>( it, value );
1705 }
else if constexpr( Tag == JsonParseTypes::KeyValue ) {
1706 return to_json_string_kv<JsonMember>( it, value );
1707 }
else if constexpr( Tag == JsonParseTypes::KeyValueArray ) {
1708 return to_json_string_kv_array<JsonMember>( it, value );
1709 }
else if constexpr( Tag == JsonParseTypes::Array ) {
1710 return to_json_string_array<JsonMember>( it, value );
1711 }
else if constexpr( Tag == JsonParseTypes::SizedArray ) {
1712 return to_json_string_sized_array<JsonMember>( it, value );
1713 }
else if constexpr( Tag == JsonParseTypes::Variant ) {
1714 return to_json_string_variant<JsonMember>( it, value );
1715 }
else if constexpr( Tag == JsonParseTypes::VariantTagged ) {
1716 return to_json_string_variant_tagged<JsonMember>( it, value );
1717 }
else if constexpr( Tag == JsonParseTypes::VariantIntrusive ) {
1718 return to_json_string_variant_intrusive<JsonMember>( it, value );
1719 }
else if constexpr( Tag == JsonParseTypes::Tuple ) {
1720 return to_json_string_tuple<JsonMember>( it, value );
1721 }
else if constexpr( Tag == JsonParseTypes::Submember ) {
1722 return to_json_string_submember<JsonMember>(
1723 it, JsonMember::json_path, value );
1724#if defined( DAW_JSON_HAS_REFLECTION )
1725 }
else if constexpr( Tag == JsonParseTypes::ReflectedClass ) {
1726 return to_json_string_reflected_class<JsonMember>( it, value );
1729 static_assert( Tag == JsonParseTypes::Unknown,
1730 "Unexpected JsonParseType" );
1731 return to_json_string_unknown<JsonMember>( it, value );
1735 template<
typename JsonMember,
typename WriteableType,
typename T>
1736 [[nodiscard]]
static constexpr WriteableType
1737 member_to_string( WriteableType it, T
const &value ) {
1738 return to_daw_json_string<JsonMember, JsonMember::expected_type>(
1739 std::move( it ), value );
1743 struct missing_required_mapping_for {};
1747 template<
typename Name>
1748 [[noreturn]] DAW_ATTRIB_NOINLINE
void missing_required_mapping_error( ) {
1749#if defined( DAW_USE_EXCEPTIONS )
1750 throw missing_required_mapping_for<Name>{ };
1756 template<
typename,
typename...>
1757 struct find_names_in_pack;
1759 template<
typename Needle,
typename... Haystack>
1760 struct find_names_in_pack<Needle,
daw::fwd_pack<Haystack...>> {
1762 static constexpr daw::simple_array<daw::string_view,
1763 sizeof...( Haystack )>
1764 names = { Haystack::name... };
1765 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1766 "Name must exist" );
1769 static DAW_CONSTEVAL std::size_t find_position( ) {
1771 for( ;
n <
sizeof...( Haystack ); ++
n ) {
1772 if( Needle::name == names[n] ) {
1776 if( n >=
sizeof...( Haystack ) ) {
1777 missing_required_mapping_error<Needle>( );
1782 static constexpr std::size_t value = find_position( );
1785 template<
typename Needle,
typename... Haystack>
1786 inline static constexpr std::size_t find_names_in_pack_v =
1787 find_names_in_pack<Needle, Haystack...>::value;
1789 template<std::size_t pos,
typename JsonMember,
typename NamePack,
1791 typename TpArgs,
typename Value,
typename VisitedMembers>
1792 static constexpr void dependent_member_to_json_str(
1794 serialization_policy<WriteableType, SerializationOptions> it,
1795 TpArgs
const &args, Value
const &v, VisitedMembers &visited_members ) {
1796 if constexpr( not has_dependent_member_v<JsonMember> ) {
1801 (void)visited_members;
1804 using base_member_t =
typename daw::conditional_t<
1805 is_json_nullable_v<JsonMember>,
1806 ident_trait<json_nullable_member_type_t, JsonMember>,
1807 daw::traits::identity<JsonMember>>::type;
1809 using dependent_member = dependent_member_t<base_member_t>;
1813 static_assert( is_a_json_type_v<JsonMember>,
1814 "Unsupported data type" );
1815 if constexpr( is_json_nullable_v<JsonMember> ) {
1816 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1818 if( not get<pos>( args ) ) {
1823 if( daw::algorithm::contains( std::data( visited_members ),
1824 daw::data_end( visited_members ),
1825 dependent_member::name ) ) {
1829 visited_members.push_back( dependent_member::name );
1830 if( not is_first ) {
1836 '"', encode_member_name_v<dependent_member>,
"\":", it.space );
1838 if constexpr( has_switcher_v<base_member_t> ) {
1839 it = member_to_string<dependent_member>(
1840 it,
typename base_member_t::switcher{ }( v ) );
1843 daw::constant<find_names_in_pack_v<dependent_member, NamePack>>;
1845 member_to_string<dependent_member>( it, get<idx::value>( args ) );
1854 struct no_visited_members_t {};
1859 template<
typename... JsonMembers>
1860 constexpr bool has_repeated_member_names( ) {
1861 if constexpr(
sizeof...( JsonMembers ) < 2 ) {
1864 daw::string_view
const names[] = { daw::string_view(
1865 std::data( JsonMembers::name ),
1866 std::size( JsonMembers::name ) )... };
1867 for( std::size_t n = 0;
n <
sizeof...( JsonMembers ); ++
n ) {
1868 for( std::size_t m = n + 1; m <
sizeof...( JsonMembers ); ++m ) {
1869 if( names[n] == names[m] ) {
1878 template<std::size_t pos,
typename JsonMember,
typename WriteableType,
1880 typename Value,
typename Visited>
1881 static constexpr void to_json_str(
1883 serialization_policy<WriteableType, SerializationOptions> &it,
1884 Tuple
const &tp, Value
const &, Visited &visited_members ) {
1885 if constexpr( std::is_same_v<Visited, no_visited_members_t> ) {
1886 (void)visited_members;
1888 DAW_CPP23_STATIC_LOCAL
constexpr auto json_member_name =
1889 daw::string_view( std::data( JsonMember::name ),
1890 std::size( JsonMember::name ) );
1891 if( daw::algorithm::contains( std::data( visited_members ),
1892 daw::data_end( visited_members ),
1893 json_member_name ) ) {
1896 visited_members.push_back( json_member_name );
1898 static_assert( is_a_json_type_v<JsonMember>,
"Unsupported data type" );
1899 if constexpr( is_json_nullable_v<JsonMember> ) {
1900 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1901 if( not concepts::nullable_value_has_value( get<pos>( tp ) ) ) {
1904 if constexpr( has_null_checker_v<JsonMember> ) {
1905 if(
typename JsonMember::is_null_checker{ }( get<pos>( tp ) ) ) {
1911 if( not is_first ) {
1916 it.write(
'"', encode_member_name_v<JsonMember>,
"\":", it.space );
1918 it = member_to_string<JsonMember>( std::move( it ), get<pos>( tp ) );
1921 template<std::size_t TupleIdx,
typename JsonMember,
1923 template<
class...>
class Tuple,
typename... Args>
1924 static constexpr void to_json_ordered_str(
1925 std::size_t &array_idx, std::size_t array_size,
1926 serialization_policy<WriteableType, SerializerOptions> &it,
1927 Tuple<Args...>
const &tp ) {
1929 using json_member_type = ordered_member_subtype_t<JsonMember>;
1930 static_assert( is_a_json_type_v<json_member_type>,
1931 "Unsupported data type" );
1935 not is_a_json_tagged_variant_v<json_member_type>,
1936 "JSON tagged variant types are not supported when inside an array "
1937 "as an ordered structure" );
1939 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1940 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1942 it.write(
"null," );
1946 it = member_to_string<json_member_type>( it, get<TupleIdx>( tp ) );
1948 if( array_idx < array_size ) {
1966 template<options::FPOutputFormat fp_output_format,
unsigned Precision,
1967 typename UInt,
typename WriteableType>
1968 constexpr WriteableType
1969 write_fixed_notation( WriteableType out_it, UInt significand,
1970 std::int32_t exponent,
unsigned digit_values,
1971 unsigned decimal_places ) {
1972 static_assert( daw::is_unsigned_v<UInt> );
1975 char *
const digits_last = digits + digit_values;
1977 char *ptr = digits_last;
1978 while( significand >= 100U ) {
1979 auto const tmp =
static_cast<std::size_t
>( significand % 100U );
1980 significand /= 100U;
1983 ptr[0] = digits100[tmp][1];
1984 ptr[1] = digits100[tmp][0];
1986 if( significand >= 10U ) {
1988 ptr[0] = digits100[
static_cast<std::size_t
>( significand )][1];
1989 ptr[1] = digits100[
static_cast<std::size_t
>( significand )][0];
1991 *--ptr =
static_cast<char>(
'0' +
static_cast<char>( significand ) );
1994 auto const put_zeros = [&]( std::size_t count ) {
1995 constexpr char zeros[] =
"00000000000000000000000000000000";
1996 constexpr std::size_t zeros_size =
sizeof( zeros ) - 1U;
1997 while( count > zeros_size ) {
1998 out_it.copy_buffer( zeros, zeros + zeros_size );
1999 count -= zeros_size;
2001 out_it.copy_buffer( zeros, zeros + count );
2003 auto const pad_fraction = [&] {
2004 if constexpr( Precision != daw::max_value<unsigned> ) {
2005 auto const fraction_digits =
static_cast<unsigned>( -exponent );
2006 if( fraction_digits < decimal_places ) {
2007 put_zeros( decimal_places - fraction_digits );
2012 if( exponent >= 0 ) {
2013 out_it.copy_buffer( digits, digits_last );
2014 put_zeros(
static_cast<std::size_t
>( exponent ) );
2015 if constexpr( fp_output_format == options::FPOutputFormat::Decimal ) {
2016 if constexpr( Precision == daw::max_value<unsigned> ) {
2017 out_it.write(
".0" );
2019 if( decimal_places != 0 ) {
2021 put_zeros( decimal_places );
2027 auto const whole_dig =
static_cast<std::int32_t
>( digit_values ) + exponent;
2028 if( whole_dig <= 0 ) {
2029 out_it.write(
"0." );
2030 put_zeros(
static_cast<std::size_t
>( -whole_dig ) );
2031 out_it.copy_buffer( digits, digits_last );
2035 char const *
const point = digits + whole_dig;
2036 out_it.copy_buffer( digits, point );
2038 out_it.copy_buffer( point, digits_last );
2046 template<options::FPOutputFormat fp_output_format,
unsigned Precision,
2047 typename UInt,
typename WriteableType>
2048 DAW_ATTRIB_NOINLINE
constexpr WriteableType
2049 write_fixed_notation_noinline( WriteableType out_it, UInt significand,
2050 std::int32_t exponent,
2051 unsigned digit_values,
2052 unsigned decimal_places ) {
2053 return write_fixed_notation<fp_output_format, Precision>(
2054 out_it, significand, exponent, digit_values, decimal_places );
2090 template<options::FPOutputFormat fp_output_format,
unsigned Precision,
2091 typename Real,
typename WriteableType>
2092 constexpr WriteableType to_chars( Real
const &value,
2093 WriteableType out_it ) {
2094 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
2095 daw::jkj::dragonbox::to_decimal(
2096 value, daw::jkj::dragonbox::policy::sign::ignore );
2097 auto const original_digits =
2098 daw::jkj::dragonbox::to_chars_detail::decimal_length(
2101 daw::max_digits10<Real> < daw::digits10<std::uintmax_t>,
2102 "The integer pow10 table must cover every Dragonbox significand "
2104 unsigned decimal_places = 0;
2105 unsigned scientific_places = 0;
2109 auto round_significand = [&](
unsigned digits )
constexpr {
2113 if( original_digits <= digits ) {
2116 auto const remove = original_digits - digits;
2117 using carrier_t =
decltype( dec.significand );
2118 auto const divisor =
2119 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
2120 auto quotient = dec.significand / divisor;
2121 auto const remainder = dec.significand % divisor;
2122 auto const halfway = divisor / 2;
2123 if( remainder > halfway or
2124 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
2127 dec.significand = quotient;
2128 dec.exponent +=
static_cast<int>( remove );
2129 if( daw::jkj::dragonbox::to_chars_detail::decimal_length(
2130 dec.significand ) > digits ) {
2132 dec.significand /= 10;
2136 if constexpr( Precision != daw::max_value<unsigned> ) {
2137 if constexpr( fp_output_format == options::FPOutputFormat::Auto ) {
2140 round_significand( Precision );
2141 }
else if constexpr( fp_output_format ==
2142 options::FPOutputFormat::Decimal ) {
2144 decimal_places = Precision;
2145 if( dec.exponent < -
static_cast<int>( Precision ) ) {
2146 using carrier_t =
decltype( dec.significand );
2147 auto const remove =
static_cast<unsigned>(
2148 -
static_cast<long long>( dec.exponent ) - Precision );
2149 if( remove > original_digits ) {
2154 dec.significand = 0;
2156 auto const divisor =
2157 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
2158 auto quotient = dec.significand / divisor;
2159 auto const remainder = dec.significand % divisor;
2160 auto const halfway = divisor / 2;
2161 if( remainder > halfway or
2162 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
2165 dec.significand = quotient;
2167 dec.exponent = -
static_cast<int>( Precision );
2169 }
else if constexpr( fp_output_format ==
2170 options::FPOutputFormat::Scientific ) {
2172 scientific_places = Precision;
2173 round_significand( Precision + 1 );
2176 unsigned const wanted = Precision + 1;
2178 daw::jkj::dragonbox::to_chars_detail::decimal_length(
2180 while( current < wanted and current < 19 ) {
2181 dec.significand *= 10;
2185 }
else if constexpr( fp_output_format ==
2186 options::FPOutputFormat::Minimum ) {
2188 round_significand( Precision );
2191 auto const digit_values =
2192 daw::jkj::dragonbox::to_chars_detail::decimal_length(
2195 auto const br = [&] {
2196 if constexpr( std::is_same_v<Real, float> ) {
2197 return daw::jkj::dragonbox::ieee754_bits( value );
2199 return daw::jkj::dragonbox::ieee754_bits(
2200 static_cast<double>( value ) );
2203 if( dec.significand == 0 ) {
2204 if( fp_output_format == options::FPOutputFormat::Decimal ) {
2206 if constexpr( Precision != daw::max_value<unsigned> ) {
2207 if( decimal_places != 0 ) {
2209 for(
unsigned n = 0;
n < decimal_places; ++
n ) {
2214 out_it.write(
".0" );
2221 if( br.is_negative( ) ) {
2224 if constexpr( fp_output_format ==
2225 options::FPOutputFormat::Scientific ) {
2228 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
2229 dec, ptr, digit_values );
2230 if( scientific_places == 0 ) {
2231 out_it.copy_buffer( buff, ptr );
2233 char const *epos = buff;
2234 while( epos != ptr and *epos !=
'e' ) {
2237 char const *dot = buff;
2238 while( dot != epos and *dot !=
'.' ) {
2242 out_it.copy_buffer( buff, epos );
2245 out_it.copy_buffer( buff, dot + 1 );
2246 out_it.copy_buffer( dot + 1, epos );
2249 dot == epos ? 0U :
static_cast<unsigned>( epos - dot - 1 );
2250 while( count < scientific_places ) {
2254 out_it.copy_buffer( epos, ptr );
2257 }
else if constexpr( fp_output_format ==
2258 options::FPOutputFormat::Auto ) {
2259 auto const whole_dig =
2260 static_cast<std::int32_t
>( digit_values ) + dec.exponent;
2261 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
2264 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
2265 dec, ptr, digit_values );
2266 out_it.copy_buffer( buff, ptr );
2270 if constexpr( fp_output_format == options::FPOutputFormat::Auto ) {
2271 return write_fixed_notation_noinline<fp_output_format, Precision>(
2272 out_it, dec.significand, dec.exponent, digit_values,
2275 return write_fixed_notation<fp_output_format, Precision>(
2276 out_it, dec.significand, dec.exponent, digit_values,