51 namespace json_details {
52 template<options::FPOutputFormat fp_output_format,
53 unsigned Precision = daw::max_value<unsigned>,
typename Real,
54 typename WriteableType>
55 constexpr WriteableType to_chars( Real
const &value,
56 WriteableType out_it );
59 namespace json_details::to_strings {
64 [[nodiscard]]
static constexpr auto to_string( std::optional<T>
const &v )
66 if( not has_value( v ) ) {
76 namespace json_details {
78 has_from_string_v, from_string( std::declval<daw::tag_t<T>>( ),
79 std::declval<std::string_view>( ) ) );
82 has_ostream_op_v,
operator<<( std::declval<std::stringstream &>( ),
83 std::declval<T const &>( ) ) );
86 has_istream_op_v,
operator>>( std::declval<std::stringstream &>( ),
87 std::declval<T const &>( ) ) );
101 std::stringstream ss{ };
103 return std::move( ss ).str( );
109 if constexpr( json_details::is_string_view_like_v<U> ) {
110 return std::string_view( std::data( value ), std::size( value ) );
111 }
else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
112 using json_details::to_strings::to_string;
114 }
else if constexpr( json_details::has_ostream_op_v<U> ) {
115 return use_stream( value );
116 }
else if constexpr( std::is_convertible_v<U, std::string_view> ) {
117 return static_cast<std::string_view
>( value );
118 }
else if constexpr( std::is_convertible_v<U, std::string> ) {
119 return static_cast<std::string
>( value );
120 }
else if constexpr( daw::is_arithmetic_v<U> ) {
122 }
else if constexpr( std::is_enum_v<U> ) {
123 return to_string(
static_cast<std::underlying_type_t<U>
>( value ) );
124 }
else if constexpr( concepts::is_nullable_value_v<U> ) {
125 using value_type = concepts::nullable_value_type_t<U>;
126 if constexpr( json_details::is_string_view_like_v<value_type> ) {
127 if constexpr( std::is_reference_v<DAW_TYPEOF(
128 concepts::nullable_value_read( value ) )> ) {
129 if( concepts::nullable_value_has_value( value ) ) {
130 return daw::string_view(
131 concepts::nullable_value_read( value ) );
133 return daw::string_view(
"null" );
135 if( concepts::nullable_value_has_value( value ) ) {
136 auto const &v = concepts::nullable_value_read( value );
137 return std::string( std::data( v ), std::size( v ) );
139 return std::string(
"null", 4 );
141 }
else if constexpr( json_details::to_strings::has_to_string_v<
143 if( concepts::nullable_value_has_value( value ) ) {
144 using json_details::to_strings::to_string;
145 return to_string( concepts::nullable_value_read( value ) );
147 using result_t = DAW_TYPEOF(
148 to_string( concepts::nullable_value_read( value ) ) );
149 return result_t{
"null" };
151 }
else if constexpr( std::is_convertible_v<value_type,
152 std::string_view> ) {
153 if( concepts::nullable_value_has_value( value ) ) {
154 return static_cast<std::string_view
>(
155 concepts::nullable_value_read( value ) );
157 return std::string_view{
"null" };
158 }
else if constexpr( std::is_convertible_v<value_type,
160 if( concepts::nullable_value_has_value( value ) ) {
161 return static_cast<std::string
>(
162 concepts::nullable_value_read( value ) );
164 return std::string(
"null" );
166 if( concepts::nullable_value_has_value( value ) ) {
167 return use_stream( concepts::nullable_value_has_value( value ) );
169 return std::string(
"null" );
176 namespace from_json_conv_details {
178 [[nodiscard]]
static auto use_stream( std::string_view sv ) {
179 std::stringstream ss{ };
191 if constexpr( std::is_same_v<T, std::string_view> or
192 std::is_same_v<T, std::optional<std::string_view>> ) {
194 }
else if constexpr( json_details::has_from_string_v<T> ) {
195 return from_string( daw::tag<T>, sv );
196 }
else if constexpr( std::is_convertible_v<std::string_view, T> ) {
197 return static_cast<T
>( sv );
198 }
else if constexpr( std::is_convertible_v<std::string, T> ) {
199 return static_cast<T
>(
static_cast<std::string
>( sv ) );
201 static_assert( json_details::has_istream_op_v<T>,
202 "Unsupported type in default to converter. Must "
203 "supply a custom one" );
204 static_assert( std::is_default_constructible_v<T>,
205 "Unsupported type in default to converter. Must "
206 "supply a custom one" );
207 return from_json_conv_details::use_stream<T>( sv );
212 namespace json_details {
214 template<
typename Char>
215 static constexpr char to_nibble_char( Char c ) {
216 auto const u =
static_cast<unsigned>(
static_cast<unsigned char>( c ) );
219 return static_cast<char>( u +
static_cast<unsigned char>(
'0' ) );
221 return static_cast<char>( ( u - 10U ) +
222 static_cast<unsigned char>(
'A' ) );
226 template<
typename WritableType>
227 static constexpr WritableType output_hex( std::uint16_t c,
229 char const nibbles[] = {
'\\',
231 to_nibble_char( ( c >> 12U ) & 0xFU ),
232 to_nibble_char( ( c >> 8U ) & 0xFU ),
233 to_nibble_char( ( c >> 4U ) & 0xFU ),
234 to_nibble_char( c & 0xFU ),
241 template<
typename WritableType>
242 static constexpr void utf32_to_utf8( std::uint32_t cp,
245 it.put(
static_cast<char>( cp ) );
250 static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
251 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
256 if( cp <= 0xFFFFU ) {
258 static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
259 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
260 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
265 if( cp <= 0x10FFFFU ) {
267 static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
268 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
269 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
270 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
280 template<
bool RestrictHigh,
typename WriteableType>
281 [[nodiscard]]
static constexpr WriteableType
307 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
311 if constexpr( RestrictHigh ) {
312 if( cp >= 0x80U and cp <= 0xFFFFU ) {
313 it = json_details::output_hex(
314 static_cast<std::uint16_t
>( cp ), it );
318 it = json_details::output_hex(
319 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
320 it = json_details::output_hex(
321 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ), it );
325 json_details::utf32_to_utf8( cp, it );
332 bool do_escape =
false,
333 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
334 bool use_scanned_write =
false,
typename WritableType,
335 typename Container DAW_ENABLEIF(
336 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )>
338 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )
339 [[nodiscard]]
static constexpr WritableType
341 using restrict_high = std::bool_constant<
342 EightBitMode != options::EightBitModes::AllowFull or
343 ( WritableType::restricted_string_output ==
344 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
345 if constexpr( do_escape ) {
346 if constexpr( use_scanned_write and
347 json_details::is_string_view_like_v<Container> ) {
348 auto const *
const data = std::data(
container );
349 auto const size = std::size(
container );
350 bool is_ascii =
true;
351 for( std::size_t n = 0; n < size; ++n ) {
352 if(
static_cast<unsigned char>( data[n] ) >= 0x80U ) {
358 auto const *first = data;
359 auto const *pos = data;
360 auto const *
const last = data + size;
361 while( pos != last ) {
362 auto const c =
static_cast<unsigned char>( *pos );
363 if( c !=
'"' and c !=
'\\' and c >= 0x20U ) {
368 it.write( daw::string_view(
369 first,
static_cast<std::size_t
>( pos - first ) ) );
394 it = json_details::output_hex(
395 static_cast<std::uint16_t
>( c ), it );
401 if( first != last ) {
402 it.write( daw::string_view(
403 first,
static_cast<std::size_t
>( last - first ) ) );
408 using iter = DAW_TYPEOF( std::begin(
container ) );
409 using it_t = utf8::unchecked::iterator<iter>;
411 auto first = it_t( std::begin(
container ) );
412 auto const last = it_t( std::end(
container ) );
413 while( first != last ) {
414 auto const last_it = first;
415 auto const cp = *first++;
416 if( last_it == first ) {
418 if constexpr( WritableType::restricted_string_output ==
419 options::RestrictedStringOutput::
423 first = it_t( std::next( first.base( ) ) );
426 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
429 if constexpr( json_details::is_string_view_like_v<Container> ) {
430 if constexpr( restrict_high::value ) {
431 for(
auto c : container ) {
433 static_cast<unsigned char>( c ) <= 0x7FU ),
434 ErrorReason::InvalidStringHighASCII );
437 it.write( daw::string_view( std::data( container ),
438 std::size( container ) ) );
440 for(
auto c : container ) {
441 if constexpr( restrict_high::value ) {
443 static_cast<unsigned char>( c ) <= 0x7FU ),
444 ErrorReason::InvalidStringHighASCII );
454 bool do_escape =
false,
455 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
456 typename WriteableType>
457 [[nodiscard]]
static constexpr WriteableType
459 if( ptr ==
nullptr ) {
462 using restrict_high = std::bool_constant<
463 EightBitMode != options::EightBitModes::AllowFull or
464 ( WriteableType::restricted_string_output ==
465 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
467 if constexpr( do_escape ) {
468 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
469 while( *chr_it.base( ) !=
'\0' ) {
470 auto const cp = *chr_it++;
471 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
473 }
else if constexpr( restrict_high::value ) {
474 auto const *
const first = ptr;
475 while( *ptr !=
'\0' ) {
477 static_cast<unsigned char>( *ptr ) <= 0x7FU ),
478 ErrorReason::InvalidStringHighASCII );
481 it.write( daw::string_view(
482 first,
static_cast<std::size_t
>( ptr - first ) ) );
490 bool do_escape =
false,
491 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
493 [[nodiscard]]
static constexpr WriteableType
496 return copy_to_iterator<do_escape, EightBitMode>( it,
"null" );
498 return copy_to_iterator<do_escape, EightBitMode>(
504 namespace json_details {
505 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
507 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
508 to_daw_json_string( WriteableType it, parse_to_t
const &value );
510 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
511 [[nodiscard]]
static constexpr WriteableType
512 to_json_string_bool( WriteableType it, parse_to_t
const &value ) {
514 if constexpr( JsonMember::literal_as_string ==
515 options::LiteralAsStringOpt::Always ) {
517 it.write(
"\"true\"" );
519 it.write(
"\"false\"" );
531 template<std::size_t idx,
typename JsonMembers,
typename WriteableType,
533 static constexpr void to_variant_string( WriteableType &it,
534 parse_to_t
const &value ) {
535 if constexpr( idx < std::variant_size_v<parse_to_t> ) {
536 if( value.index( ) != idx ) {
537 to_variant_string<idx + 1, JsonMembers>( it, value );
540 using element_t =
typename JsonMembers::json_elements;
542 typename pack_element<idx, typename element_t::element_map_t>::type;
543 it = to_daw_json_string<JsonMember, JsonMember::expected_type>(
544 it, daw::get_nt<idx>( value ) );
548 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
549 [[nodiscard]]
static constexpr WriteableType
550 to_json_string_variant( WriteableType it, parse_to_t
const &value ) {
552 assert( value.index( ) >= 0 );
553 to_variant_string<0, JsonMember>( it, value );
557 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
558 [[nodiscard]]
static constexpr WriteableType
559 to_json_string_variant_tagged( WriteableType it,
560 parse_to_t
const &value ) {
562 to_variant_string<0, JsonMember>( it, value );
566 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
567 [[nodiscard]]
static constexpr WriteableType
568 to_json_string_variant_intrusive( WriteableType it,
569 parse_to_t
const &value ) {
571 to_variant_string<0, JsonMember>( it, value );
575 template<
typename ,
typename =
void>
576 inline constexpr bool has_null_checker_v =
false;
578 template<
typename JsonMember>
579 inline constexpr bool has_null_checker_v<
580 JsonMember, std::void_t<typename JsonMember::is_null_checker>> =
581 not std::is_same_v<use_default, typename JsonMember::is_null_checker>;
583 template<
typename JsonMember,
typename WriteableType,
typename Optional>
584 [[nodiscard]]
static constexpr WriteableType
585 to_json_string_null( WriteableType it, Optional
const &value ) {
587 if constexpr( has_null_checker_v<JsonMember> ) {
589 using is_null_checker_t =
typename JsonMember::is_null_checker;
590 if( is_null_checker_t{ }( value ) ) {
594 }
else if constexpr( has_op_bool_v<Optional> ) {
595 if( not
static_cast<bool>( value ) ) {
603 if( not concepts::nullable_value_has_value( value ) ) {
608 using member_type =
typename JsonMember::member_type;
609 return to_daw_json_string<member_type, member_type::expected_type>(
611 if constexpr( concepts::is_nullable_value_v<Optional> ) {
612 return concepts::nullable_value_traits<Optional>::read( value );
613 }
else if constexpr( json_details::has_op_star_v<Optional> ) {
623 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
624 [[nodiscard]]
static constexpr WriteableType
625 to_json_string_real( WriteableType it, parse_to_t
const &value ) {
628 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
629 "value must be convertible to specified type in class contract" );
631 if constexpr( std::is_floating_point_v<json_result_t<JsonMember>> ) {
632 if( daw::cxmath::is_nan( value ) ) {
633 if constexpr( JsonMember::literal_as_string ==
634 options::LiteralAsStringOpt::Never or
635 JsonMember::allow_number_errors ==
636 options::JsonNumberErrors::None or
637 JsonMember::allow_number_errors ==
638 options::JsonNumberErrors::AllowInf ) {
641 it.write(
"\"NaN\"" );
644 }
else if( daw::cxmath::is_inf( value ) ) {
645 if constexpr( JsonMember::literal_as_string ==
646 options::LiteralAsStringOpt::Never or
647 JsonMember::allow_number_errors ==
648 options::JsonNumberErrors::None or
649 JsonMember::allow_number_errors ==
650 options::JsonNumberErrors::AllowNaN ) {
654 it.write(
"\"-Infinity\"" );
656 it.write(
"\"Infinity\"" );
663 if constexpr( JsonMember::literal_as_string ==
664 options::LiteralAsStringOpt::Always ) {
667 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
668 static_assert(
sizeof( parse_to_t ) <=
sizeof(
double ) );
669 if constexpr( has_fp_precision_v<JsonMember> ) {
670 it = to_chars<JsonMember::fp_output_format, JsonMember::precision>(
673 it = to_chars<JsonMember::fp_output_format>( value, it );
676 using std::to_string;
677 using to_strings::to_string;
678 it = utils::copy_to_iterator( it,
to_string( value ) );
680 if constexpr( JsonMember::literal_as_string ==
681 options::LiteralAsStringOpt::Always ) {
688 using base_int_type_impl = std::underlying_type<T>;
691 using base_int_type_t =
692 typename daw::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
693 daw::traits::identity<T>>::type;
695 DAW_ATTRIB_INLINE DAW_CONSTEVAL std::array<char[2], 100>
697 auto result = std::array<char[2], 100>{ };
698 for( std::size_t n = 0;
n < 100; ++
n ) {
700 static_cast<char>( (
n % 10 ) +
static_cast<unsigned char>(
'0' ) );
702 static_cast<char>( (
n / 10 ) +
static_cast<unsigned char>(
'0' ) );
706 inline constexpr auto digits100 = make_digits100( );
709 static constexpr void reverse( T *first, T *last ) {
712 DAW_ASSUME( first and last );
713 DAW_ASSUME( first <= last );
714 auto rpos = last - first;
716 while( lpos < rpos ) {
718 auto tmp = std::move( first[lpos] );
719 first[lpos] = std::move( first[rpos] );
720 first[rpos] = std::move( tmp );
725 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
726 [[nodiscard]]
static constexpr WriteableType
727 to_json_string_signed( WriteableType it, parse_to_t
const &value ) {
730 std::is_convertible_v<parse_to_t, json_base_type_t<JsonMember>>,
731 "value must be convertible to specified type in class contract" );
733 using std::to_string;
734 using to_strings::to_string;
735 using under_type = base_int_type_t<parse_to_t>;
737 if constexpr( std::is_enum_v<parse_to_t> or
738 daw::is_integral_v<parse_to_t> ) {
739 auto v =
static_cast<under_type
>( value );
741 char buff[daw::digits10<under_type> + 10]{ };
742 char *num_start = buff;
744 if constexpr( JsonMember::literal_as_string ==
745 options::LiteralAsStringOpt::Always ) {
755 auto const tmp = -
static_cast<std::size_t
>( v % 10 );
757 *ptr++ = digits100[tmp][0];
759 if constexpr( JsonMember::literal_as_string ==
760 options::LiteralAsStringOpt::Always ) {
763 it.copy_buffer( buff, ptr );
772 auto const tmp =
static_cast<std::size_t
>( v % 100 );
774 ptr[0] = digits100[tmp][0];
775 ptr[1] = digits100[tmp][1];
779 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
782 reverse( num_start, ptr );
783 if constexpr( JsonMember::literal_as_string ==
784 options::LiteralAsStringOpt::Always ) {
787 it.copy_buffer( buff, ptr );
790 if constexpr( JsonMember::literal_as_string ==
791 options::LiteralAsStringOpt::Always ) {
795 it = utils::copy_to_iterator( it,
to_string( value ) );
796 if constexpr( JsonMember::literal_as_string ==
797 options::LiteralAsStringOpt::Always ) {
804 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
805 [[nodiscard]]
static constexpr WriteableType
806 to_json_string_unsigned( WriteableType it, parse_to_t
const &value ) {
809 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
810 "value must be convertible to specified type in class contract" );
812 using std::to_string;
813 using to_strings::to_string;
814 using under_type = base_int_type_t<parse_to_t>;
815 if constexpr( JsonMember::literal_as_string ==
816 options::LiteralAsStringOpt::Always ) {
819 if constexpr( std::is_same_v<under_type, bool> ) {
820 if(
static_cast<bool>( value ) ) {
825 }
else if constexpr( std::is_enum_v<parse_to_t> or
826 daw::is_integral_v<parse_to_t> ) {
827 auto v =
static_cast<under_type
>( value );
829 if( DAW_UNLIKELY( v == 0 ) ) {
833 char buff[daw::digits10<under_type> + 10U]{ };
836 auto const tmp =
static_cast<std::size_t
>( v % 100U );
838 ptr[0] = digits100[tmp][0];
839 ptr[1] = digits100[tmp][1];
843 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
845 reverse( buff, ptr );
846 it.copy_buffer( buff, ptr );
850 it = utils::copy_to_iterator( it,
to_string( value ) );
852 if constexpr( JsonMember::literal_as_string ==
853 options::LiteralAsStringOpt::Always ) {
861 namespace utils_details {
862 template<
typename Integer>
864 using parse_to_t = Integer;
865 using base_type = parse_to_t;
866 static constexpr options::LiteralAsStringOpt literal_as_string =
867 options::LiteralAsStringOpt::Never;
871 template<
typename Integer,
typename WriteableType>
873 Integer
const &value ) {
874 static_assert( daw::is_integral_v<Integer> );
876 if constexpr( daw::is_unsigned_v<Integer> ) {
877 return json_details::to_json_string_unsigned<
878 utils_details::number<Integer>>( it, value );
880 return json_details::to_json_string_signed<
881 utils_details::number<Integer>>( it, value );
886 namespace json_details {
887 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
888 [[nodiscard]]
static constexpr WriteableType
889 to_json_string_string_raw( WriteableType it, parse_to_t
const &value ) {
892 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
893 "Value must be convertible to specialized type in "
894 "json_data_contract" );
897 if( std::size( value ) > 0U ) {
898 it = utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
905 template<
typename JsonMember,
typename =
void>
906 inline constexpr options::EscapeValidUTF8 escape_output_v =
907 options::EscapeValidUTF8::Validate;
909 template<
typename JsonMember>
910 inline constexpr options::EscapeValidUTF8 escape_output_v<
911 JsonMember, std::void_t<
decltype( JsonMember::escape_output )>> =
912 JsonMember::escape_output;
914 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
915 [[nodiscard]]
static constexpr WriteableType
916 to_json_string_string_escaped( WriteableType it,
917 parse_to_t
const &value ) {
919 it = utils::copy_to_iterator<escape_output_v<JsonMember> !=
920 options::EscapeValidUTF8::AssumeValid,
921 JsonMember::eight_bit_mode,
true>( it, value );
927 [[nodiscard]]
static constexpr bool is_null( std::optional<T>
const &v ) {
928 return not
static_cast<bool>( v );
932 [[nodiscard]]
static constexpr bool is_null( T
const & ) {
936 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
937 [[nodiscard]]
static constexpr WriteableType
938 to_json_string_date( WriteableType it, parse_to_t
const &value ) {
941 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
942 "value must be convertible to specified type in class contract" );
944 using json_details::is_null;
946 if( is_null( value ) ) {
951 datetime::ymdhms civil = datetime::time_point_to_civil( value );
952 it = utils::integer_to_string( it, civil.year );
954 if( civil.month < 10 ) {
957 it = utils::integer_to_string( it, civil.month );
959 if( civil.day < 10 ) {
962 it = utils::integer_to_string( it, civil.day );
964 if( civil.hour < 10 ) {
967 it = utils::integer_to_string( it, civil.hour );
969 if( civil.minute < 10 ) {
972 it = utils::integer_to_string( it, civil.minute );
974 if( civil.second < 10 ) {
977 it = utils::integer_to_string( it, civil.second );
978 if( civil.attosecond > 0 ) {
979 auto fractional_digits = std::size_t{ 18 };
980 while( civil.attosecond % 10 == 0 ) {
981 civil.attosecond /= 10;
985 auto const digit_count =
static_cast<std::size_t
>(
986 daw::cxmath::count_digits( civil.attosecond ) );
987 while( digit_count < fractional_digits ) {
991 it = utils::integer_to_string( it, civil.attosecond );
997 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
998 [[nodiscard]]
static constexpr WriteableType
999 to_json_string_unknown( WriteableType it, parse_to_t
const &value ) {
1001 return utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
1005 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1006 [[nodiscard]]
static constexpr WriteableType
1007 to_json_string_class( WriteableType it, parse_to_t
const &value ) {
1010 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>> or
1011 std::is_same_v<parse_to_t,
1012 json_result_t<JsonMember>>,
1015 "value must be convertible to specified type in class contract" );
1017 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
1018 return json_data_contract_trait_t<typename JsonMember::wrapped_type>::
1022 typename JsonMember::wrapped_type>::to_json_data( value ),
1024 }
else if constexpr( is_json_map_alias_v<parse_to_t> ) {
1025 return json_data_contract_trait_t<parse_to_t>::serialize(
1027 }
else if constexpr( std::is_empty_v<parse_to_t> and
1028 std::is_default_constructible_v<parse_to_t> and
1029 not has_json_data_contract_trait_v<parse_to_t> ) {
1033 static_assert( is_submember_tagged_variant_v<parse_to_t>,
1034 "Could not find appropriate mapping or to_json_data "
1035 "member of json_data_contract" );
1036 return json_data_contract_trait_t<parse_to_t>::serialize( it, value );
1040 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1041 [[nodiscard]]
static constexpr WriteableType
1042 to_json_string_reflected_class( WriteableType it,
1043 parse_to_t
const &value ) {
1045 return JsonMember::serialize( it, value );
1048 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1049 [[nodiscard]]
static constexpr WriteableType
1050 to_json_string_custom( WriteableType it, parse_to_t
const &value ) {
1053 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1054 "value must be convertible to specified type in class contract" );
1056 if constexpr( JsonMember::custom_json_type ==
1057 options::JsonCustomTypes::String ) {
1061 if constexpr( daw::is_callable_r_v<WriteableType,
1062 typename JsonMember::to_converter_t,
1065 it =
typename JsonMember::to_converter_t{ }( it, value );
1067 it = utils::copy_to_iterator(
1068 it,
typename JsonMember::to_converter_t{ }( value ) );
1071 if constexpr( JsonMember::custom_json_type ==
1072 options::JsonCustomTypes::String ) {
1078 template<
typename JsonMember,
typename WriteableType,
1081 DAW_ATTRIB_INLINE
constexpr serialization_policy<WriteableType,
1082 SerializationOptions>
1083 to_daw_json_string_tuple(
1084 serialization_policy<WriteableType, SerializationOptions> it,
1085 parse_to_t
const &value, std::index_sequence<Is...> ) {
1087 auto const to_daw_json_string_help = [&](
auto Idx ) {
1088 using index = daw::remove_cvref_t<
decltype( Idx )>;
1089 using pack_element = tuple_elements_pack<parse_to_t>;
1090 using T = std::tuple_element_t<index::value,
1091 typename JsonMember::sub_member_list>;
1093 it = to_daw_json_string<T, T::expected_type>(
1094 it, pack_element::template get<index::value>( value ) );
1095 if constexpr( index::value + 1 <
sizeof...( Is ) ) {
1100 (void)to_daw_json_string_help;
1102 daw::empty_t
const expander[]{
1103 ( to_daw_json_string_help( daw::constant_v<Is> ),
1104 daw::empty_t{ } )...,
1111 template<
typename JsonMember,
typename WriteableType,
1113 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1114 SerializationOptions>
1115 to_json_string_tuple(
1116 serialization_policy<WriteableType, SerializationOptions> it,
1117 parse_to_t
const &value ) {
1119 using tuple_t = json_result_t<JsonMember>;
1121 using element_pack = tuple_elements_pack<
typename daw::conditional_t<
1122 is_tuple_v<tuple_t>,
1123 daw::traits::identity<tuple_t>,
1124 json_details::identity_parts<tp_from_struct_binding_result_t,
1125 parse_to_t>>::type>;
1128 std::is_convertible_v<parse_to_t, tuple_t>,
1129 "value must be convertible to specified type in class contract" );
1134 if constexpr( is_tuple_v<tuple_t> ) {
1135 it = to_daw_json_string_tuple<JsonMember>(
1136 it, value, std::make_index_sequence<element_pack::size>{ } );
1138 auto value2 = to_tuple_impl( DAW_FWD( value ) );
1140 using value2_t = tp_from_struct_binding_result_t<parse_to_t>;
1141 it = to_daw_json_string_tuple<json_base::json_tuple<value2_t>>(
1142 it, value2, std::make_index_sequence<element_pack::size>{ } );
1145 if constexpr( element_pack::size > 0 ) {
1146 if constexpr( element_pack::size > 0 and
1147 it.output_trailing_comma ==
1148 options::OutputTrailingComma::Yes ) {
1158 is_view_like_v, ( (
void)( std::begin( std::declval<T &>( ) ) ),
1159 (
void)( std::end( std::declval<T &>( ) ) ),
1160 (
void)( std::declval<typename T::value_type>( ) ) ) );
1162 template<
typename JsonMember,
typename WriteableType,
1164 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1165 SerializationOptions>
1166 to_json_string_array(
1167 serialization_policy<WriteableType, SerializationOptions> it,
1168 parse_to_t
const &value ) {
1170 using array_t = json_result_t<JsonMember>;
1171 if constexpr( is_view_like_v<array_t> ) {
1173 std::is_convertible_v<parse_to_t, array_t>,
1174 "value must be convertible to specified type in class contract" );
1177 is_pointer_like_v<array_t>,
1178 "This is a special case for pointer like(T*, unique_ptr<T>, "
1179 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1180 "encode the size of the data with the pointer. Will take any "
1181 "Container like type, but std::span like types work too" );
1183 is_view_like_v<parse_to_t>,
1184 "This is a special case for pointer like(T*, unique_ptr<T>, "
1185 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1186 "encode the size of the data with the pointer. Will take any "
1187 "Container like type, but std::span like types work too" );
1192 auto first = std::begin( value );
1193 auto last = std::end( value );
1194 bool const has_elements = first != last;
1195 while( first != last ) {
1197 it = to_daw_json_string<
typename JsonMember::json_element_t,
1198 JsonMember::json_element_t::expected_type>(
1201 if( first != last ) {
1206 if constexpr( it.output_trailing_comma ==
1207 options::OutputTrailingComma::Yes ) {
1208 if( has_elements ) {
1212 if( has_elements ) {
1219 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1220 [[nodiscard]]
static constexpr WriteableType
1221 to_json_string_sized_array( WriteableType it, parse_to_t
const &value ) {
1222 return to_json_string_array<JsonMember>( it, value );
1225 template<
typename Key,
typename Value>
1226 static constexpr Key
const &
1227 json_get_key( std::pair<Key, Value>
const &kv ) {
1231 template<
typename Key,
typename Value>
1232 static constexpr Value
const &
1233 json_get_value( std::pair<Key, Value>
const &kv ) {
1237 template<
typename JsonMember,
typename WriteableType,
1239 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1241 to_json_string_kv_array(
1242 serialization_policy<WriteableType, SerializeOptions> it,
1243 parse_to_t
const &value ) {
1246 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1247 "value must be convertible to specified type in class contract" );
1248 using key_t =
typename JsonMember::json_key_t;
1249 using value_t =
typename JsonMember::json_value_t;
1252 auto first = std::begin( value );
1253 auto last = std::end( value );
1254 bool const has_elements = first != last;
1255 while( first != last ) {
1261 it.write(
"\"", key_t::name,
"\":", it.space );
1263 it = to_daw_json_string<key_t, key_t::expected_type>(
1264 it, json_get_key( *first ) );
1269 it.write(
"\"", value_t::name,
"\":", it.space );
1271 it = to_daw_json_string<value_t, value_t::expected_type>(
1272 it, json_get_value( *first ) );
1275 if constexpr( it.output_trailing_comma ==
1276 options::OutputTrailingComma::Yes ) {
1277 if( has_elements ) {
1284 if( first != last ) {
1289 if constexpr( it.output_trailing_comma ==
1290 options::OutputTrailingComma::Yes ) {
1291 if( has_elements ) {
1295 if( has_elements ) {
1302 template<
typename JsonMember,
typename WriteableType,
1304 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1305 SerializationOptions>
1307 serialization_policy<WriteableType, SerializationOptions> it,
1308 parse_to_t
const &value ) {
1312 auto first = std::begin( value );
1313 auto last = std::end( value );
1314 bool const has_elements = first != last;
1315 while( first != last ) {
1316 auto const &v = *first;
1318 it = to_daw_json_string<
typename JsonMember::json_key_t,
1319 JsonMember::json_key_t::expected_type>(
1320 it, json_get_key( v ) );
1321 it.write(
':', it.space );
1322 it = to_daw_json_string<
typename JsonMember::json_element_t,
1323 JsonMember::json_element_t::expected_type>(
1324 it, json_get_value( v ) );
1326 if( first != last ) {
1331 if constexpr( it.output_trailing_comma ==
1332 options::OutputTrailingComma::Yes ) {
1333 if( has_elements ) {
1337 if( has_elements ) {
1344 template<
typename JsonMember,
typename WriteableType,
typename T>
1345 [[nodiscard]]
static constexpr WriteableType
1346 to_json_string_submember( WriteableType it, daw::string_view path,
1349 template<
typename JsonMember,
typename WriteableType,
typename T>
1350 [[nodiscard]]
static constexpr WriteableType
1351 to_json_string_submember_array( WriteableType it, daw::string_view path,
1353 auto const index = pop_json_path( path );
1358 index.current.size( ) == 1 and
1359 index.current.front( ) ==
'0',
1360 ErrorReason::OutputError );
1365 if( path.empty( ) ) {
1366 using member_type =
typename JsonMember::member_type;
1367 it = to_daw_json_string<member_type, member_type::expected_type>(
1370 it = to_json_string_submember<JsonMember>( it, path, value );
1373 if constexpr( it.output_trailing_comma ==
1374 options::OutputTrailingComma::Yes ) {
1382 template<
typename JsonMember,
typename WriteableType,
typename T>
1383 [[nodiscard]]
static constexpr WriteableType
1384 to_json_string_submember( WriteableType it, daw::string_view path,
1386 auto const path_item = pop_json_path( path );
1387 if( path_item.current.empty( ) ) {
1389 ErrorReason::OutputError );
1390 return to_json_string_submember_array<JsonMember>( it, path, value );
1397 auto name = path_item.current;
1398 while( not name.empty( ) ) {
1399 if( name.front( ) ==
'\\' ) {
1400 name.remove_prefix( );
1403 it.put( name.front( ) );
1404 name.remove_prefix( );
1406 it.write(
"\":", it.space );
1408 if( path_item.found_char ==
'[' ) {
1409 it = to_json_string_submember_array<JsonMember>( it, path, value );
1410 }
else if( path.empty( ) ) {
1411 using member_type =
typename JsonMember::member_type;
1412 it = to_daw_json_string<member_type, member_type::expected_type>(
1415 it = to_json_string_submember<JsonMember>( it, path, value );
1418 if constexpr( it.output_trailing_comma ==
1419 options::OutputTrailingComma::Yes ) {
1427 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
1428 typename parse_to_t>
1429 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
1430 to_daw_json_string( WriteableType it, parse_to_t
const &value ) {
1431 if constexpr( Tag == JsonParseTypes::Real ) {
1432 return to_json_string_real<JsonMember>( it, value );
1433 }
else if constexpr( Tag == JsonParseTypes::Signed ) {
1434 return to_json_string_signed<JsonMember>( it, value );
1435 }
else if constexpr( Tag == JsonParseTypes::Unsigned ) {
1436 return to_json_string_unsigned<JsonMember>( it, value );
1437 }
else if constexpr( Tag == JsonParseTypes::Null ) {
1438 return to_json_string_null<JsonMember>( it, value );
1439 }
else if constexpr( Tag == JsonParseTypes::Bool ) {
1440 return to_json_string_bool<JsonMember>( it, value );
1441 }
else if constexpr( Tag == JsonParseTypes::StringRaw ) {
1442 return to_json_string_string_raw<JsonMember>( it, value );
1443 }
else if constexpr( Tag == JsonParseTypes::StringEscaped or
1444 Tag == JsonParseTypes::StringInsitu ) {
1445 return to_json_string_string_escaped<JsonMember>( it, value );
1446 }
else if constexpr( Tag == JsonParseTypes::Date ) {
1447 return to_json_string_date<JsonMember>( it, value );
1448 }
else if constexpr( Tag == JsonParseTypes::Custom ) {
1449 return to_json_string_custom<JsonMember>( it, value );
1450 }
else if constexpr( Tag == JsonParseTypes::Class ) {
1451 return to_json_string_class<JsonMember>( it, value );
1452 }
else if constexpr( Tag == JsonParseTypes::KeyValue ) {
1453 return to_json_string_kv<JsonMember>( it, value );
1454 }
else if constexpr( Tag == JsonParseTypes::KeyValueArray ) {
1455 return to_json_string_kv_array<JsonMember>( it, value );
1456 }
else if constexpr( Tag == JsonParseTypes::Array ) {
1457 return to_json_string_array<JsonMember>( it, value );
1458 }
else if constexpr( Tag == JsonParseTypes::SizedArray ) {
1459 return to_json_string_sized_array<JsonMember>( it, value );
1460 }
else if constexpr( Tag == JsonParseTypes::Variant ) {
1461 return to_json_string_variant<JsonMember>( it, value );
1462 }
else if constexpr( Tag == JsonParseTypes::VariantTagged ) {
1463 return to_json_string_variant_tagged<JsonMember>( it, value );
1464 }
else if constexpr( Tag == JsonParseTypes::VariantIntrusive ) {
1465 return to_json_string_variant_intrusive<JsonMember>( it, value );
1466 }
else if constexpr( Tag == JsonParseTypes::Tuple ) {
1467 return to_json_string_tuple<JsonMember>( it, value );
1468 }
else if constexpr( Tag == JsonParseTypes::Submember ) {
1469 return to_json_string_submember<JsonMember>(
1470 it, JsonMember::json_path, value );
1471#if defined( DAW_JSON_HAS_REFLECTION )
1472 }
else if constexpr( Tag == JsonParseTypes::ReflectedClass ) {
1473 return to_json_string_reflected_class<JsonMember>( it, value );
1476 static_assert( Tag == JsonParseTypes::Unknown,
1477 "Unexpected JsonParseType" );
1478 return to_json_string_unknown<JsonMember>( it, value );
1482 template<
typename JsonMember,
typename WriteableType,
typename T>
1483 [[nodiscard]]
static constexpr WriteableType
1484 member_to_string( WriteableType it, T
const &value ) {
1485 return to_daw_json_string<JsonMember, JsonMember::expected_type>(
1486 std::move( it ), value );
1490 struct missing_required_mapping_for {};
1494 template<
typename Name>
1495 [[noreturn]] DAW_ATTRIB_NOINLINE
void missing_required_mapping_error( ) {
1496#if defined( DAW_USE_EXCEPTIONS )
1497 throw missing_required_mapping_for<Name>{ };
1503 template<
typename,
typename...>
1504 struct find_names_in_pack;
1506 template<
typename Needle,
typename... Haystack>
1507 struct find_names_in_pack<Needle,
daw::fwd_pack<Haystack...>> {
1509 static constexpr daw::simple_array<daw::string_view,
1510 sizeof...( Haystack )>
1511 names = { Haystack::name... };
1512 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1513 "Name must exist" );
1516 static DAW_CONSTEVAL std::size_t find_position( ) {
1518 for( ;
n <
sizeof...( Haystack ); ++
n ) {
1519 if( Needle::name == names[n] ) {
1523 if( n >=
sizeof...( Haystack ) ) {
1524 missing_required_mapping_error<Needle>( );
1529 static constexpr std::size_t value = find_position( );
1532 template<
typename Needle,
typename... Haystack>
1533 inline static constexpr std::size_t find_names_in_pack_v =
1534 find_names_in_pack<Needle, Haystack...>::value;
1536 template<std::size_t pos,
typename JsonMember,
typename NamePack,
1538 typename TpArgs,
typename Value,
typename VisitedMembers>
1539 static constexpr void dependent_member_to_json_str(
1541 serialization_policy<WriteableType, SerializationOptions> it,
1542 TpArgs
const &args, Value
const &v, VisitedMembers &visited_members ) {
1543 if constexpr( not has_dependent_member_v<JsonMember> ) {
1548 (void)visited_members;
1551 using base_member_t =
typename daw::conditional_t<
1552 is_json_nullable_v<JsonMember>,
1553 ident_trait<json_nullable_member_type_t, JsonMember>,
1554 daw::traits::identity<JsonMember>>::type;
1556 using dependent_member = dependent_member_t<base_member_t>;
1560 static_assert( is_a_json_type_v<JsonMember>,
1561 "Unsupported data type" );
1562 if constexpr( is_json_nullable_v<JsonMember> ) {
1563 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1565 if( not get<pos>( args ) ) {
1570 if( daw::algorithm::contains( std::data( visited_members ),
1571 daw::data_end( visited_members ),
1572 dependent_member::name ) ) {
1576 visited_members.push_back( dependent_member::name );
1577 if( not is_first ) {
1582 it.write(
'"', dependent_member::name,
"\":", it.space );
1584 if constexpr( has_switcher_v<base_member_t> ) {
1585 it = member_to_string<dependent_member>(
1586 it,
typename base_member_t::switcher{ }( v ) );
1589 daw::constant<find_names_in_pack_v<dependent_member, NamePack>>;
1591 member_to_string<dependent_member>( it, get<idx::value>( args ) );
1597 template<std::size_t pos,
typename JsonMember,
typename WriteableType,
1599 typename Value,
typename Visited>
1600 static constexpr void to_json_str(
1602 serialization_policy<WriteableType, SerializationOptions> &it,
1603 Tuple
const &tp, Value
const &, Visited &visited_members ) {
1604 DAW_CPP23_STATIC_LOCAL
constexpr auto json_member_name =
1605 daw::string_view( std::data( JsonMember::name ),
1606 std::size( JsonMember::name ) );
1607 if( daw::algorithm::contains( std::data( visited_members ),
1608 daw::data_end( visited_members ),
1609 json_member_name ) ) {
1612 visited_members.push_back( json_member_name );
1613 static_assert( is_a_json_type_v<JsonMember>,
"Unsupported data type" );
1614 if constexpr( is_json_nullable_v<JsonMember> ) {
1615 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1616 if( not concepts::nullable_value_has_value( get<pos>( tp ) ) ) {
1621 if( not is_first ) {
1626 it.write(
'"', JsonMember::name,
"\":", it.space );
1628 it = member_to_string<JsonMember>( std::move( it ), get<pos>( tp ) );
1631 template<std::size_t TupleIdx,
typename JsonMember,
1633 template<
class...>
class Tuple,
typename... Args>
1634 static constexpr void to_json_ordered_str(
1635 std::size_t &array_idx, std::size_t array_size,
1636 serialization_policy<WriteableType, SerializerOptions> &it,
1637 Tuple<Args...>
const &tp ) {
1639 using json_member_type = ordered_member_subtype_t<JsonMember>;
1640 static_assert( is_a_json_type_v<json_member_type>,
1641 "Unsupported data type" );
1645 not is_a_json_tagged_variant_v<json_member_type>,
1646 "JSON tagged variant types are not supported when inside an array "
1647 "as an ordered structure" );
1649 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1650 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1652 it.write(
"null," );
1656 it = member_to_string<json_member_type>( it, get<TupleIdx>( tp ) );
1658 if( array_idx < array_size ) {
1697 template<options::FPOutputFormat fp_output_format,
unsigned Precision,
1698 typename Real,
typename WriteableType>
1699 constexpr WriteableType to_chars( Real
const &value,
1700 WriteableType out_it ) {
1701 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
1702 daw::jkj::dragonbox::to_decimal(
1703 value, daw::jkj::dragonbox::policy::sign::ignore );
1704 auto const original_digits =
1705 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1708 daw::max_digits10<Real> < daw::digits10<std::uintmax_t>,
1709 "The integer pow10 table must cover every Dragonbox significand "
1711 unsigned decimal_places = 0;
1712 unsigned scientific_places = 0;
1716 auto round_significand = [&](
unsigned digits )
constexpr {
1720 if( original_digits <= digits ) {
1723 auto const remove = original_digits - digits;
1724 using carrier_t =
decltype( dec.significand );
1725 auto const divisor =
1726 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
1727 auto quotient = dec.significand / divisor;
1728 auto const remainder = dec.significand % divisor;
1729 auto const halfway = divisor / 2;
1730 if( remainder > halfway or
1731 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
1734 dec.significand = quotient;
1735 dec.exponent +=
static_cast<int>( remove );
1736 if( daw::jkj::dragonbox::to_chars_detail::decimal_length(
1737 dec.significand ) > digits ) {
1739 dec.significand /= 10;
1743 if constexpr( Precision != daw::max_value<unsigned> ) {
1744 if constexpr( fp_output_format == options::FPOutputFormat::Auto ) {
1747 round_significand( Precision );
1748 }
else if constexpr( fp_output_format ==
1749 options::FPOutputFormat::Decimal ) {
1751 decimal_places = Precision;
1752 if( dec.exponent < -
static_cast<int>( Precision ) ) {
1753 using carrier_t =
decltype( dec.significand );
1754 auto const remove =
static_cast<unsigned>(
1755 -
static_cast<long long>( dec.exponent ) - Precision );
1756 if( remove > original_digits ) {
1761 dec.significand = 0;
1763 auto const divisor =
1764 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
1765 auto quotient = dec.significand / divisor;
1766 auto const remainder = dec.significand % divisor;
1767 auto const halfway = divisor / 2;
1768 if( remainder > halfway or
1769 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
1772 dec.significand = quotient;
1774 dec.exponent = -
static_cast<int>( Precision );
1776 }
else if constexpr( fp_output_format ==
1777 options::FPOutputFormat::Scientific ) {
1779 scientific_places = Precision;
1780 round_significand( Precision + 1 );
1783 unsigned const wanted = Precision + 1;
1785 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1787 while( current < wanted and current < 19 ) {
1788 dec.significand *= 10;
1792 }
else if constexpr( fp_output_format ==
1793 options::FPOutputFormat::Minimum ) {
1795 round_significand( Precision );
1798 auto const digit_values =
1799 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1803 static_cast<std::int32_t
>( digit_values ) + dec.exponent;
1805 auto const br = [&] {
1806 if constexpr( std::is_same_v<Real, float> ) {
1807 return daw::jkj::dragonbox::ieee754_bits( value );
1809 return daw::jkj::dragonbox::ieee754_bits(
1810 static_cast<double>( value ) );
1813 if( dec.significand == 0 ) {
1814 if( fp_output_format == options::FPOutputFormat::Decimal ) {
1816 if constexpr( Precision != daw::max_value<unsigned> ) {
1817 if( decimal_places != 0 ) {
1819 for(
unsigned n = 0;
n < decimal_places; ++
n ) {
1824 out_it.write(
".0" );
1831 if( br.is_negative( ) ) {
1834 if constexpr( fp_output_format ==
1835 options::FPOutputFormat::Scientific ) {
1838 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1839 dec, ptr, digit_values );
1840 if( scientific_places == 0 ) {
1841 out_it.copy_buffer( buff, ptr );
1843 char const *epos = buff;
1844 while( epos != ptr and *epos !=
'e' ) {
1847 char const *dot = buff;
1848 while( dot != epos and *dot !=
'.' ) {
1852 out_it.copy_buffer( buff, epos );
1855 out_it.copy_buffer( buff, dot + 1 );
1856 out_it.copy_buffer( dot + 1, epos );
1859 dot == epos ? 0U :
static_cast<unsigned>( epos - dot - 1 );
1860 while( count < scientific_places ) {
1864 out_it.copy_buffer( epos, ptr );
1867 }
else if constexpr( fp_output_format ==
1868 options::FPOutputFormat::Auto ) {
1869 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
1872 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1873 dec, ptr, digit_values );
1874 out_it.copy_buffer( buff, ptr );
1878 if( dec.exponent < 0 ) {
1879 if( whole_dig < 0 ) {
1880 out_it.write(
"0." );
1884 }
while( whole_dig < 0 );
1885 out_it = utils::integer_to_string( out_it, dec.significand );
1886 if constexpr( Precision != daw::max_value<unsigned> ) {
1887 for(
auto n =
static_cast<unsigned>( -dec.exponent );
1897 daw::cxmath::pow10(
static_cast<std::size_t
>( -dec.exponent ) );
1898 auto const p1val = dec.significand / p1pow;
1899 out_it = utils::integer_to_string( out_it, p1val );
1904 auto const p2val = dec.significand - ( p1val * p1pow );
1907 auto const l10_p1val = daw::cxmath::count_digits( p1val );
1908 auto const l10_p2val = daw::cxmath::count_digits( p2val );
1909 auto const extra_zeros =
1910 static_cast<int>( digit_values ) - ( l10_p2val + l10_p1val );
1911 for(
int n = 0;
n < extra_zeros; ++
n ) {
1915 out_it = utils::integer_to_string( out_it, p2val );
1916 if constexpr( Precision != daw::max_value<unsigned> ) {
1917 for(
auto n =
static_cast<unsigned>( -dec.exponent );
1925 out_it = utils::integer_to_string( out_it, dec.significand );
1927 while( dec.exponent > 0 ) {
1931 if( fp_output_format == options::FPOutputFormat::Decimal ) {
1932 if constexpr( Precision == daw::max_value<unsigned> ) {
1936 if( decimal_places != 0 ) {
1938 for(
unsigned n = 0;
n < decimal_places; ++
n ) {