52 namespace json_details {
53 template<options::FPOutputFormat fp_output_format,
54 unsigned Precision = daw::max_value<unsigned>,
typename Real,
55 typename WriteableType>
56 constexpr WriteableType to_chars( Real
const &value,
57 WriteableType out_it );
60 namespace json_details::to_strings {
65 [[nodiscard]]
static constexpr auto to_string( std::optional<T>
const &v )
67 if( not has_value( v ) ) {
77 namespace json_details {
79 has_from_string_v, from_string( std::declval<daw::tag_t<T>>( ),
80 std::declval<std::string_view>( ) ) );
83 has_ostream_op_v,
operator<<( std::declval<std::stringstream &>( ),
84 std::declval<T const &>( ) ) );
87 has_istream_op_v,
operator>>( std::declval<std::stringstream &>( ),
88 std::declval<T const &>( ) ) );
102 std::stringstream ss{ };
104 return std::move( ss ).str( );
110 if constexpr( json_details::is_string_view_like_v<U> ) {
111 return std::string_view( std::data( value ), std::size( value ) );
112 }
else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
113 using json_details::to_strings::to_string;
115 }
else if constexpr( json_details::has_ostream_op_v<U> ) {
116 return use_stream( value );
117 }
else if constexpr( std::is_convertible_v<U, std::string_view> ) {
118 return static_cast<std::string_view
>( value );
119 }
else if constexpr( std::is_convertible_v<U, std::string> ) {
120 return static_cast<std::string
>( value );
121 }
else if constexpr( daw::is_arithmetic_v<U> ) {
123 }
else if constexpr( std::is_enum_v<U> ) {
124 return to_string(
static_cast<std::underlying_type_t<U>
>( value ) );
125 }
else if constexpr( concepts::is_nullable_value_v<U> ) {
126 using value_type = concepts::nullable_value_type_t<U>;
127 if constexpr( json_details::is_string_view_like_v<value_type> ) {
128 if constexpr( std::is_reference_v<DAW_TYPEOF(
129 concepts::nullable_value_read( value ) )> ) {
130 if( concepts::nullable_value_has_value( value ) ) {
131 return daw::string_view(
132 concepts::nullable_value_read( value ) );
134 return daw::string_view(
"null" );
136 if( concepts::nullable_value_has_value( value ) ) {
137 auto const &v = concepts::nullable_value_read( value );
138 return std::string( std::data( v ), std::size( v ) );
140 return std::string(
"null", 4 );
142 }
else if constexpr( json_details::to_strings::has_to_string_v<
144 if( concepts::nullable_value_has_value( value ) ) {
145 using json_details::to_strings::to_string;
146 return to_string( concepts::nullable_value_read( value ) );
148 using result_t = DAW_TYPEOF(
149 to_string( concepts::nullable_value_read( value ) ) );
150 return result_t{
"null" };
152 }
else if constexpr( std::is_convertible_v<value_type,
153 std::string_view> ) {
154 if( concepts::nullable_value_has_value( value ) ) {
155 return static_cast<std::string_view
>(
156 concepts::nullable_value_read( value ) );
158 return std::string_view{
"null" };
159 }
else if constexpr( std::is_convertible_v<value_type,
161 if( concepts::nullable_value_has_value( value ) ) {
162 return static_cast<std::string
>(
163 concepts::nullable_value_read( value ) );
165 return std::string(
"null" );
167 if( concepts::nullable_value_has_value( value ) ) {
168 return use_stream( concepts::nullable_value_has_value( value ) );
170 return std::string(
"null" );
177 namespace from_json_conv_details {
179 [[nodiscard]]
static auto use_stream( std::string_view sv ) {
180 std::stringstream ss{ };
192 if constexpr( std::is_same_v<T, std::string_view> or
193 std::is_same_v<T, std::optional<std::string_view>> ) {
195 }
else if constexpr( json_details::has_from_string_v<T> ) {
196 return from_string( daw::tag<T>, sv );
197 }
else if constexpr( std::is_convertible_v<std::string_view, T> ) {
198 return static_cast<T
>( sv );
199 }
else if constexpr( std::is_convertible_v<std::string, T> ) {
200 return static_cast<T
>(
static_cast<std::string
>( sv ) );
202 static_assert( json_details::has_istream_op_v<T>,
203 "Unsupported type in default to converter. Must "
204 "supply a custom one" );
205 static_assert( std::is_default_constructible_v<T>,
206 "Unsupported type in default to converter. Must "
207 "supply a custom one" );
208 return from_json_conv_details::use_stream<T>( sv );
213 namespace json_details {
215 template<
typename Char>
216 static constexpr char to_nibble_char( Char c ) {
217 auto const u =
static_cast<unsigned>(
static_cast<unsigned char>( c ) );
220 return static_cast<char>( u +
static_cast<unsigned char>(
'0' ) );
222 return static_cast<char>( ( u - 10U ) +
223 static_cast<unsigned char>(
'A' ) );
227 template<
typename WritableType>
228 static constexpr WritableType output_hex( std::uint16_t c,
230 char const nibbles[] = {
'\\',
232 to_nibble_char( ( c >> 12U ) & 0xFU ),
233 to_nibble_char( ( c >> 8U ) & 0xFU ),
234 to_nibble_char( ( c >> 4U ) & 0xFU ),
235 to_nibble_char( c & 0xFU ),
242 template<
typename WritableType>
243 static constexpr void utf32_to_utf8( std::uint32_t cp,
246 it.put(
static_cast<char>( cp ) );
251 static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
252 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
257 if( cp <= 0xFFFFU ) {
259 static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
260 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
261 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
266 if( cp <= 0x10FFFFU ) {
268 static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
269 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
270 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
271 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
281 template<
bool RestrictHigh,
typename WriteableType>
282 [[nodiscard]]
static constexpr WriteableType
309 json_details::output_hex(
static_cast<std::uint16_t
>( cp ), it );
312 if constexpr( RestrictHigh ) {
313 if( cp >= 0x80U and cp <= 0xFFFFU ) {
314 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
319 it = json_details::output_hex(
320 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
321 it = json_details::output_hex(
322 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ), it );
326 json_details::utf32_to_utf8( cp, it );
333 bool do_escape =
false,
334 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
335 bool use_scanned_write =
false,
typename WritableType,
336 typename Container DAW_ENABLEIF(
337 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )>
339 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )
340 [[nodiscard]]
static constexpr WritableType
342 using restrict_high = std::bool_constant<
343 EightBitMode != options::EightBitModes::AllowFull or
344 ( WritableType::restricted_string_output ==
345 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
346 if constexpr( do_escape ) {
347 if constexpr( use_scanned_write and
348 json_details::is_string_view_like_v<Container> ) {
349 auto const *
const data = std::data(
container );
350 auto const size = std::size(
container );
351 bool is_ascii =
true;
352 for( std::size_t n = 0; n < size; ++n ) {
353 if(
static_cast<unsigned char>( data[n] ) >= 0x80U ) {
359 auto const *first = data;
360 auto const *pos = data;
361 auto const *
const last = data + size;
362 while( pos != last ) {
363 auto const c =
static_cast<unsigned char>( *pos );
364 if( c !=
'"' and c !=
'\\' and c >= 0x20U ) {
369 it.write( daw::string_view(
370 first,
static_cast<std::size_t
>( pos - first ) ) );
395 it = json_details::output_hex(
396 static_cast<std::uint16_t
>( c ), it );
402 if( first != last ) {
403 it.write( daw::string_view(
404 first,
static_cast<std::size_t
>( last - first ) ) );
409 using iter = DAW_TYPEOF( std::begin(
container ) );
410 using it_t = utf8::unchecked::iterator<iter>;
412 auto first = it_t( std::begin(
container ) );
413 auto const last = it_t( std::end(
container ) );
414 while( first != last ) {
415 auto const last_it = first;
416 auto const cp = *first++;
417 if( last_it == first ) {
419 if constexpr( WritableType::restricted_string_output ==
420 options::RestrictedStringOutput::
424 first = it_t( std::next( first.base( ) ) );
427 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
430 if constexpr( json_details::is_string_view_like_v<Container> ) {
431 if constexpr( restrict_high::value ) {
432 for(
auto c : container ) {
434 static_cast<unsigned char>( c ) <= 0x7FU ),
435 ErrorReason::InvalidStringHighASCII );
438 it.write( daw::string_view( std::data( container ),
439 std::size( container ) ) );
441 for(
auto c : container ) {
442 if constexpr( restrict_high::value ) {
444 static_cast<unsigned char>( c ) <= 0x7FU ),
445 ErrorReason::InvalidStringHighASCII );
455 bool do_escape =
false,
456 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
457 typename WriteableType>
458 [[nodiscard]]
static constexpr WriteableType
460 if( ptr ==
nullptr ) {
463 using restrict_high = std::bool_constant<
464 EightBitMode != options::EightBitModes::AllowFull or
465 ( WriteableType::restricted_string_output ==
466 options::RestrictedStringOutput::OnlyAllow7bitStrings )>;
468 if constexpr( do_escape ) {
469 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
470 while( *chr_it.base( ) !=
'\0' ) {
471 auto const cp = *chr_it++;
472 it = escape_codepoint_to_iterator<restrict_high::value>( it, cp );
474 }
else if constexpr( restrict_high::value ) {
475 auto const *
const first = ptr;
476 while( *ptr !=
'\0' ) {
478 static_cast<unsigned char>( *ptr ) <= 0x7FU ),
479 ErrorReason::InvalidStringHighASCII );
482 it.write( daw::string_view(
483 first,
static_cast<std::size_t
>( ptr - first ) ) );
491 bool do_escape =
false,
492 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
494 [[nodiscard]]
static constexpr WriteableType
497 return copy_to_iterator<do_escape, EightBitMode>( it,
"null" );
499 return copy_to_iterator<do_escape, EightBitMode>(
505 namespace json_details {
506 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
508 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
509 to_daw_json_string( WriteableType it, parse_to_t
const &value );
511 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
512 [[nodiscard]]
static constexpr WriteableType
513 to_json_string_bool( WriteableType it, parse_to_t
const &value ) {
515 if constexpr( JsonMember::literal_as_string ==
516 options::LiteralAsStringOpt::Always ) {
518 it.write(
"\"true\"" );
520 it.write(
"\"false\"" );
532 template<std::size_t idx,
typename JsonMembers,
typename WriteableType,
534 static constexpr void to_variant_string( WriteableType &it,
535 parse_to_t
const &value ) {
536 if constexpr( idx < std::variant_size_v<parse_to_t> ) {
537 if( value.index( ) != idx ) {
538 to_variant_string<idx + 1, JsonMembers>( it, value );
541 using element_t =
typename JsonMembers::json_elements;
543 typename pack_element<idx, typename element_t::element_map_t>::type;
544 it = to_daw_json_string<JsonMember, JsonMember::expected_type>(
545 it, daw::get_nt<idx>( value ) );
549 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
550 [[nodiscard]]
static constexpr WriteableType
551 to_json_string_variant( WriteableType it, parse_to_t
const &value ) {
553 assert( value.index( ) >= 0 );
554 to_variant_string<0, JsonMember>( it, value );
558 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
559 [[nodiscard]]
static constexpr WriteableType
560 to_json_string_variant_tagged( WriteableType it,
561 parse_to_t
const &value ) {
563 to_variant_string<0, JsonMember>( it, value );
567 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
568 [[nodiscard]]
static constexpr WriteableType
569 to_json_string_variant_intrusive( WriteableType it,
570 parse_to_t
const &value ) {
572 to_variant_string<0, JsonMember>( it, value );
576 template<
typename ,
typename =
void>
577 inline constexpr bool has_null_checker_v =
false;
579 template<
typename JsonMember>
580 inline constexpr bool has_null_checker_v<
581 JsonMember, std::void_t<typename JsonMember::is_null_checker>> =
582 not std::is_same_v<use_default, typename JsonMember::is_null_checker>;
584 template<
typename JsonMember,
typename WriteableType,
typename Optional>
585 [[nodiscard]]
static constexpr WriteableType
586 to_json_string_null( WriteableType it, Optional
const &value ) {
588 if constexpr( has_null_checker_v<JsonMember> ) {
590 using is_null_checker_t =
typename JsonMember::is_null_checker;
591 if( is_null_checker_t{ }( value ) ) {
595 }
else if constexpr( has_op_bool_v<Optional> ) {
596 if( not
static_cast<bool>( value ) ) {
604 if( not concepts::nullable_value_has_value( value ) ) {
609 using member_type =
typename JsonMember::member_type;
610 return to_daw_json_string<member_type, member_type::expected_type>(
612 if constexpr( concepts::is_nullable_value_v<Optional> ) {
613 return concepts::nullable_value_traits<Optional>::read( value );
614 }
else if constexpr( json_details::has_op_star_v<Optional> ) {
624 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
625 [[nodiscard]]
static constexpr WriteableType
626 to_json_string_real( WriteableType it, parse_to_t
const &value ) {
629 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
630 "value must be convertible to specified type in class contract" );
632 if constexpr( std::is_floating_point_v<json_result_t<JsonMember>> ) {
633 if( daw::cxmath::is_nan( value ) ) {
634 if constexpr( JsonMember::literal_as_string ==
635 options::LiteralAsStringOpt::Never or
636 JsonMember::allow_number_errors ==
637 options::JsonNumberErrors::None or
638 JsonMember::allow_number_errors ==
639 options::JsonNumberErrors::AllowInf ) {
642 it.write(
"\"NaN\"" );
645 }
else if( daw::cxmath::is_inf( value ) ) {
646 if constexpr( JsonMember::literal_as_string ==
647 options::LiteralAsStringOpt::Never or
648 JsonMember::allow_number_errors ==
649 options::JsonNumberErrors::None or
650 JsonMember::allow_number_errors ==
651 options::JsonNumberErrors::AllowNaN ) {
655 it.write(
"\"-Infinity\"" );
657 it.write(
"\"Infinity\"" );
664 if constexpr( JsonMember::literal_as_string ==
665 options::LiteralAsStringOpt::Always ) {
668 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
669 static_assert(
sizeof( parse_to_t ) <=
sizeof(
double ) );
670 if constexpr( has_fp_precision_v<JsonMember> ) {
671 it = to_chars<JsonMember::fp_output_format, JsonMember::precision>(
674 it = to_chars<JsonMember::fp_output_format>( value, it );
677 using std::to_string;
678 using to_strings::to_string;
679 it = utils::copy_to_iterator( it,
to_string( value ) );
681 if constexpr( JsonMember::literal_as_string ==
682 options::LiteralAsStringOpt::Always ) {
689 using base_int_type_impl = std::underlying_type<T>;
692 using base_int_type_t =
693 typename daw::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
694 daw::traits::identity<T>>::type;
696 DAW_ATTRIB_INLINE DAW_CONSTEVAL std::array<char[2], 100>
698 auto result = std::array<char[2], 100>{ };
699 for( std::size_t n = 0;
n < 100; ++
n ) {
701 static_cast<char>( (
n % 10 ) +
static_cast<unsigned char>(
'0' ) );
703 static_cast<char>( (
n / 10 ) +
static_cast<unsigned char>(
'0' ) );
707 inline constexpr auto digits100 = make_digits100( );
710 static constexpr void reverse( T *first, T *last ) {
713 DAW_ASSUME( first and last );
714 DAW_ASSUME( first <= last );
715 auto rpos = last - first;
717 while( lpos < rpos ) {
719 auto tmp = std::move( first[lpos] );
720 first[lpos] = std::move( first[rpos] );
721 first[rpos] = std::move( tmp );
726 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
727 [[nodiscard]]
static constexpr WriteableType
728 to_json_string_signed( WriteableType it, parse_to_t
const &value ) {
731 daw::is_explicitly_convertible_v<parse_to_t,
732 json_base_type_t<JsonMember>>,
733 "value must be convertible to specified type in class contract" );
735 using std::to_string;
736 using to_strings::to_string;
737 using under_type = base_int_type_t<parse_to_t>;
739 if constexpr( std::is_enum_v<parse_to_t> or
740 daw::is_integral_v<parse_to_t> ) {
741 auto v =
static_cast<under_type
>( value );
743 char buff[daw::digits10<under_type> + 10]{ };
744 char *num_start = buff;
746 if constexpr( JsonMember::literal_as_string ==
747 options::LiteralAsStringOpt::Always ) {
757 auto const tmp = -
static_cast<std::size_t
>( v % 10 );
759 *ptr++ = digits100[tmp][0];
761 if constexpr( JsonMember::literal_as_string ==
762 options::LiteralAsStringOpt::Always ) {
765 it.copy_buffer( buff, ptr );
774 auto const tmp =
static_cast<std::size_t
>( v % 100 );
776 ptr[0] = digits100[tmp][0];
777 ptr[1] = digits100[tmp][1];
781 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
784 reverse( num_start, ptr );
785 if constexpr( JsonMember::literal_as_string ==
786 options::LiteralAsStringOpt::Always ) {
789 it.copy_buffer( buff, ptr );
792 if constexpr( JsonMember::literal_as_string ==
793 options::LiteralAsStringOpt::Always ) {
797 it = utils::copy_to_iterator( it,
to_string( value ) );
798 if constexpr( JsonMember::literal_as_string ==
799 options::LiteralAsStringOpt::Always ) {
806 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
807 [[nodiscard]]
static constexpr WriteableType
808 to_json_string_unsigned( WriteableType it, parse_to_t
const &value ) {
811 daw::is_explicitly_convertible_v<parse_to_t,
812 json_result_t<JsonMember>>,
813 "value must be convertible to specified type in class contract" );
815 using std::to_string;
816 using to_strings::to_string;
817 using under_type = base_int_type_t<parse_to_t>;
818 if constexpr( JsonMember::literal_as_string ==
819 options::LiteralAsStringOpt::Always ) {
822 if constexpr( std::is_same_v<under_type, bool> ) {
823 if(
static_cast<bool>( value ) ) {
828 }
else if constexpr( std::is_enum_v<parse_to_t> or
829 daw::is_integral_v<parse_to_t> ) {
830 auto v =
static_cast<under_type
>( value );
832 if( DAW_UNLIKELY( v == 0 ) ) {
836 char buff[daw::digits10<under_type> + 10U]{ };
839 auto const tmp =
static_cast<std::size_t
>( v % 100U );
841 ptr[0] = digits100[tmp][0];
842 ptr[1] = digits100[tmp][1];
846 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
848 reverse( buff, ptr );
849 it.copy_buffer( buff, ptr );
853 it = utils::copy_to_iterator( it,
to_string( value ) );
855 if constexpr( JsonMember::literal_as_string ==
856 options::LiteralAsStringOpt::Always ) {
864 namespace utils_details {
865 template<
typename Integer>
867 using parse_to_t = Integer;
868 using base_type = parse_to_t;
869 static constexpr options::LiteralAsStringOpt literal_as_string =
870 options::LiteralAsStringOpt::Never;
874 template<
typename Integer,
typename WriteableType>
876 Integer
const &value ) {
877 static_assert( daw::is_integral_v<Integer> );
879 if constexpr( daw::is_unsigned_v<Integer> ) {
880 return json_details::to_json_string_unsigned<
881 utils_details::number<Integer>>( it, value );
883 return json_details::to_json_string_signed<
884 utils_details::number<Integer>>( it, value );
889 namespace json_details {
890 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
891 [[nodiscard]]
static constexpr WriteableType
892 to_json_string_string_raw( WriteableType it, parse_to_t
const &value ) {
895 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
896 "Value must be convertible to specialized type in "
897 "json_data_contract" );
900 if( std::size( value ) > 0U ) {
901 it = utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
908 template<
typename JsonMember,
typename =
void>
909 inline constexpr options::EscapeValidUTF8 escape_output_v =
910 options::EscapeValidUTF8::Validate;
912 template<
typename JsonMember>
913 inline constexpr options::EscapeValidUTF8 escape_output_v<
914 JsonMember, std::void_t<
decltype( JsonMember::escape_output )>> =
915 JsonMember::escape_output;
917 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
918 [[nodiscard]]
static constexpr WriteableType
919 to_json_string_string_escaped( WriteableType it,
920 parse_to_t
const &value ) {
922 it = utils::copy_to_iterator<escape_output_v<JsonMember> !=
923 options::EscapeValidUTF8::AssumeValid,
924 JsonMember::eight_bit_mode,
931 [[nodiscard]]
static constexpr bool is_null( std::optional<T>
const &v ) {
932 return not
static_cast<bool>( v );
936 [[nodiscard]]
static constexpr bool is_null( T
const & ) {
940 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
941 [[nodiscard]]
static constexpr WriteableType
942 to_json_string_date( WriteableType it, parse_to_t
const &value ) {
945 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
946 "value must be convertible to specified type in class contract" );
948 using json_details::is_null;
950 if( is_null( value ) ) {
955 datetime::ymdhms civil = datetime::time_point_to_civil( value );
956 it = utils::integer_to_string( it, civil.year );
958 if( civil.month < 10 ) {
961 it = utils::integer_to_string( it, civil.month );
963 if( civil.day < 10 ) {
966 it = utils::integer_to_string( it, civil.day );
968 if( civil.hour < 10 ) {
971 it = utils::integer_to_string( it, civil.hour );
973 if( civil.minute < 10 ) {
976 it = utils::integer_to_string( it, civil.minute );
978 if( civil.second < 10 ) {
981 it = utils::integer_to_string( it, civil.second );
982 if( civil.attosecond > 0 ) {
983 auto fractional_digits = std::size_t{ 18 };
984 while( civil.attosecond % 10 == 0 ) {
985 civil.attosecond /= 10;
989 auto const digit_count =
static_cast<std::size_t
>(
990 daw::cxmath::count_digits( civil.attosecond ) );
991 while( digit_count < fractional_digits ) {
995 it = utils::integer_to_string( it, civil.attosecond );
1001 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1002 [[nodiscard]]
static constexpr WriteableType
1003 to_json_string_unknown( WriteableType it, parse_to_t
const &value ) {
1005 return utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
1009 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1010 [[nodiscard]]
static constexpr WriteableType
1011 to_json_string_class( WriteableType it, parse_to_t
const &value ) {
1014 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>> or
1015 std::is_same_v<parse_to_t,
1016 json_result_t<JsonMember>>,
1019 "value must be convertible to specified type in class contract" );
1021 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
1022 return json_data_contract_trait_t<typename JsonMember::wrapped_type>::
1026 typename JsonMember::wrapped_type>::to_json_data( value ),
1028 }
else if constexpr( is_json_map_alias_v<parse_to_t> ) {
1029 return json_data_contract_trait_t<parse_to_t>::serialize(
1031 }
else if constexpr( std::is_empty_v<parse_to_t> and
1032 std::is_default_constructible_v<parse_to_t> and
1033 not has_json_data_contract_trait_v<parse_to_t> ) {
1037 static_assert( is_submember_tagged_variant_v<parse_to_t>,
1038 "Could not find appropriate mapping or to_json_data "
1039 "member of json_data_contract" );
1040 return json_data_contract_trait_t<parse_to_t>::serialize( it, value );
1044 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1045 [[nodiscard]]
static constexpr WriteableType
1046 to_json_string_reflected_class( WriteableType it,
1047 parse_to_t
const &value ) {
1049 return JsonMember::serialize( it, value );
1052 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1053 [[nodiscard]]
static constexpr WriteableType
1054 to_json_string_custom( WriteableType it, parse_to_t
const &value ) {
1057 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1058 "value must be convertible to specified type in class contract" );
1060 if constexpr( JsonMember::custom_json_type ==
1061 options::JsonCustomTypes::String ) {
1065 if constexpr( daw::is_callable_r_v<WriteableType,
1066 typename JsonMember::to_converter_t,
1069 it =
typename JsonMember::to_converter_t{ }( it, value );
1071 it = utils::copy_to_iterator(
1072 it,
typename JsonMember::to_converter_t{ }( value ) );
1075 if constexpr( JsonMember::custom_json_type ==
1076 options::JsonCustomTypes::String ) {
1082 template<
typename JsonMember,
typename WriteableType,
1085 DAW_ATTRIB_INLINE
constexpr serialization_policy<WriteableType,
1086 SerializationOptions>
1087 to_daw_json_string_tuple(
1088 serialization_policy<WriteableType, SerializationOptions> it,
1089 parse_to_t
const &value, std::index_sequence<Is...> ) {
1091 auto const to_daw_json_string_help = [&](
auto Idx ) {
1092 using index = daw::remove_cvref_t<
decltype( Idx )>;
1093 using pack_element = tuple_elements_pack<parse_to_t>;
1094 using T = std::tuple_element_t<index::value,
1095 typename JsonMember::sub_member_list>;
1097 it = to_daw_json_string<T, T::expected_type>(
1098 it, pack_element::template get<index::value>( value ) );
1099 if constexpr( index::value + 1 <
sizeof...( Is ) ) {
1104 (void)to_daw_json_string_help;
1106 daw::empty_t
const expander[]{
1107 ( to_daw_json_string_help( daw::constant_v<Is> ),
1108 daw::empty_t{ } )...,
1115 template<
typename JsonMember,
typename WriteableType,
1117 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1118 SerializationOptions>
1119 to_json_string_tuple(
1120 serialization_policy<WriteableType, SerializationOptions> it,
1121 parse_to_t
const &value ) {
1123 using tuple_t = json_result_t<JsonMember>;
1125 using element_pack = tuple_elements_pack<
typename daw::conditional_t<
1126 is_tuple_v<tuple_t>,
1127 daw::traits::identity<tuple_t>,
1128 json_details::identity_parts<tp_from_struct_binding_result_t,
1129 parse_to_t>>::type>;
1132 std::is_convertible_v<parse_to_t, tuple_t>,
1133 "value must be convertible to specified type in class contract" );
1138 if constexpr( is_tuple_v<tuple_t> ) {
1139 it = to_daw_json_string_tuple<JsonMember>(
1140 it, value, std::make_index_sequence<element_pack::size>{ } );
1142 auto value2 = to_tuple_impl( DAW_FWD( value ) );
1144 using value2_t = tp_from_struct_binding_result_t<parse_to_t>;
1145 it = to_daw_json_string_tuple<json_base::json_tuple<value2_t>>(
1146 it, value2, std::make_index_sequence<element_pack::size>{ } );
1149 if constexpr( element_pack::size > 0 ) {
1150 if constexpr( element_pack::size > 0 and
1151 it.output_trailing_comma ==
1152 options::OutputTrailingComma::Yes ) {
1162 is_view_like_v, ( (
void)( std::begin( std::declval<T &>( ) ) ),
1163 (
void)( std::end( std::declval<T &>( ) ) ),
1164 (
void)( std::declval<typename T::value_type>( ) ) ) );
1166 template<
typename JsonMember,
typename WriteableType,
1168 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1169 SerializationOptions>
1170 to_json_string_array(
1171 serialization_policy<WriteableType, SerializationOptions> it,
1172 parse_to_t
const &value ) {
1174 using array_t = json_result_t<JsonMember>;
1175 if constexpr( is_view_like_v<array_t> ) {
1177 std::is_convertible_v<parse_to_t, array_t>,
1178 "value must be convertible to specified type in class contract" );
1181 is_pointer_like_v<array_t>,
1182 "This is a special case for pointer like(T*, unique_ptr<T>, "
1183 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1184 "encode the size of the data with the pointer. Will take any "
1185 "Container like type, but std::span like types work too" );
1187 is_view_like_v<parse_to_t>,
1188 "This is a special case for pointer like(T*, unique_ptr<T>, "
1189 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1190 "encode the size of the data with the pointer. Will take any "
1191 "Container like type, but std::span like types work too" );
1196 auto first = std::begin( value );
1197 auto last = std::end( value );
1198 bool const has_elements = first != last;
1199 while( first != last ) {
1201 it = to_daw_json_string<
typename JsonMember::json_element_t,
1202 JsonMember::json_element_t::expected_type>(
1205 if( first != last ) {
1210 if constexpr( it.output_trailing_comma ==
1211 options::OutputTrailingComma::Yes ) {
1212 if( has_elements ) {
1216 if( has_elements ) {
1223 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1224 [[nodiscard]]
static constexpr WriteableType
1225 to_json_string_sized_array( WriteableType it, parse_to_t
const &value ) {
1226 return to_json_string_array<JsonMember>( it, value );
1229 template<
typename Key,
typename Value>
1230 static constexpr Key
const &
1231 json_get_key( std::pair<Key, Value>
const &kv ) {
1235 template<
typename Key,
typename Value>
1236 static constexpr Value
const &
1237 json_get_value( std::pair<Key, Value>
const &kv ) {
1241 template<
typename JsonMember,
typename WriteableType,
1243 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1245 to_json_string_kv_array(
1246 serialization_policy<WriteableType, SerializeOptions> it,
1247 parse_to_t
const &value ) {
1250 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1251 "value must be convertible to specified type in class contract" );
1252 using key_t =
typename JsonMember::json_key_t;
1253 using value_t =
typename JsonMember::json_value_t;
1256 auto first = std::begin( value );
1257 auto last = std::end( value );
1258 bool const has_elements = first != last;
1259 while( first != last ) {
1265 it.write(
"\"", key_t::name,
"\":", it.space );
1267 it = to_daw_json_string<key_t, key_t::expected_type>(
1268 it, json_get_key( *first ) );
1273 it.write(
"\"", value_t::name,
"\":", it.space );
1275 it = to_daw_json_string<value_t, value_t::expected_type>(
1276 it, json_get_value( *first ) );
1279 if constexpr( it.output_trailing_comma ==
1280 options::OutputTrailingComma::Yes ) {
1281 if( has_elements ) {
1288 if( first != last ) {
1293 if constexpr( it.output_trailing_comma ==
1294 options::OutputTrailingComma::Yes ) {
1295 if( has_elements ) {
1299 if( has_elements ) {
1306 template<
typename JsonMember,
typename WriteableType,
1308 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1309 SerializationOptions>
1311 serialization_policy<WriteableType, SerializationOptions> it,
1312 parse_to_t
const &value ) {
1316 auto first = std::begin( value );
1317 auto last = std::end( value );
1318 bool const has_elements = first != last;
1319 while( first != last ) {
1320 auto const &v = *first;
1322 it = to_daw_json_string<
typename JsonMember::json_key_t,
1323 JsonMember::json_key_t::expected_type>(
1324 it, json_get_key( v ) );
1325 it.write(
':', it.space );
1326 it = to_daw_json_string<
typename JsonMember::json_element_t,
1327 JsonMember::json_element_t::expected_type>(
1328 it, json_get_value( v ) );
1330 if( first != last ) {
1335 if constexpr( it.output_trailing_comma ==
1336 options::OutputTrailingComma::Yes ) {
1337 if( has_elements ) {
1341 if( has_elements ) {
1348 template<
typename JsonMember,
typename WriteableType,
typename T>
1349 [[nodiscard]]
static constexpr WriteableType
1350 to_json_string_submember( WriteableType it, daw::string_view path,
1353 template<
typename JsonMember,
typename WriteableType,
typename T>
1354 [[nodiscard]]
static constexpr WriteableType
1355 to_json_string_submember_array( WriteableType it, daw::string_view path,
1357 auto const index = pop_json_path( path );
1362 index.current.size( ) == 1 and
1363 index.current.front( ) ==
'0',
1364 ErrorReason::OutputError );
1369 if( path.empty( ) ) {
1370 using member_type =
typename JsonMember::member_type;
1371 it = to_daw_json_string<member_type, member_type::expected_type>(
1374 it = to_json_string_submember<JsonMember>( it, path, value );
1377 if constexpr( it.output_trailing_comma ==
1378 options::OutputTrailingComma::Yes ) {
1386 template<
typename JsonMember,
typename WriteableType,
typename T>
1387 [[nodiscard]]
static constexpr WriteableType
1388 to_json_string_submember( WriteableType it, daw::string_view path,
1390 auto const path_item = pop_json_path( path );
1391 if( path_item.current.empty( ) ) {
1393 ErrorReason::OutputError );
1394 return to_json_string_submember_array<JsonMember>( it, path, value );
1401 auto name = path_item.current;
1402 while( not name.empty( ) ) {
1403 if( name.front( ) ==
'\\' ) {
1404 name.remove_prefix( );
1407 it.put( name.front( ) );
1408 name.remove_prefix( );
1410 it.write(
"\":", it.space );
1412 if( path_item.found_char ==
'[' ) {
1413 it = to_json_string_submember_array<JsonMember>( it, path, value );
1414 }
else if( path.empty( ) ) {
1415 using member_type =
typename JsonMember::member_type;
1416 it = to_daw_json_string<member_type, member_type::expected_type>(
1419 it = to_json_string_submember<JsonMember>( it, path, value );
1422 if constexpr( it.output_trailing_comma ==
1423 options::OutputTrailingComma::Yes ) {
1431 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
1432 typename parse_to_t>
1433 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
1434 to_daw_json_string( WriteableType it, parse_to_t
const &value ) {
1435 if constexpr( Tag == JsonParseTypes::Real ) {
1436 return to_json_string_real<JsonMember>( it, value );
1437 }
else if constexpr( Tag == JsonParseTypes::Signed ) {
1438 return to_json_string_signed<JsonMember>( it, value );
1439 }
else if constexpr( Tag == JsonParseTypes::Unsigned ) {
1440 return to_json_string_unsigned<JsonMember>( it, value );
1441 }
else if constexpr( Tag == JsonParseTypes::Null ) {
1442 return to_json_string_null<JsonMember>( it, value );
1443 }
else if constexpr( Tag == JsonParseTypes::Bool ) {
1444 return to_json_string_bool<JsonMember>( it, value );
1445 }
else if constexpr( Tag == JsonParseTypes::StringRaw ) {
1446 return to_json_string_string_raw<JsonMember>( it, value );
1447 }
else if constexpr( Tag == JsonParseTypes::StringEscaped or
1448 Tag == JsonParseTypes::StringInsitu ) {
1449 return to_json_string_string_escaped<JsonMember>( it, value );
1450 }
else if constexpr( Tag == JsonParseTypes::Date ) {
1451 return to_json_string_date<JsonMember>( it, value );
1452 }
else if constexpr( Tag == JsonParseTypes::Custom ) {
1453 return to_json_string_custom<JsonMember>( it, value );
1454 }
else if constexpr( Tag == JsonParseTypes::Class ) {
1455 return to_json_string_class<JsonMember>( it, value );
1456 }
else if constexpr( Tag == JsonParseTypes::KeyValue ) {
1457 return to_json_string_kv<JsonMember>( it, value );
1458 }
else if constexpr( Tag == JsonParseTypes::KeyValueArray ) {
1459 return to_json_string_kv_array<JsonMember>( it, value );
1460 }
else if constexpr( Tag == JsonParseTypes::Array ) {
1461 return to_json_string_array<JsonMember>( it, value );
1462 }
else if constexpr( Tag == JsonParseTypes::SizedArray ) {
1463 return to_json_string_sized_array<JsonMember>( it, value );
1464 }
else if constexpr( Tag == JsonParseTypes::Variant ) {
1465 return to_json_string_variant<JsonMember>( it, value );
1466 }
else if constexpr( Tag == JsonParseTypes::VariantTagged ) {
1467 return to_json_string_variant_tagged<JsonMember>( it, value );
1468 }
else if constexpr( Tag == JsonParseTypes::VariantIntrusive ) {
1469 return to_json_string_variant_intrusive<JsonMember>( it, value );
1470 }
else if constexpr( Tag == JsonParseTypes::Tuple ) {
1471 return to_json_string_tuple<JsonMember>( it, value );
1472 }
else if constexpr( Tag == JsonParseTypes::Submember ) {
1473 return to_json_string_submember<JsonMember>(
1474 it, JsonMember::json_path, value );
1475#if defined( DAW_JSON_HAS_REFLECTION )
1476 }
else if constexpr( Tag == JsonParseTypes::ReflectedClass ) {
1477 return to_json_string_reflected_class<JsonMember>( it, value );
1480 static_assert( Tag == JsonParseTypes::Unknown,
1481 "Unexpected JsonParseType" );
1482 return to_json_string_unknown<JsonMember>( it, value );
1486 template<
typename JsonMember,
typename WriteableType,
typename T>
1487 [[nodiscard]]
static constexpr WriteableType
1488 member_to_string( WriteableType it, T
const &value ) {
1489 return to_daw_json_string<JsonMember, JsonMember::expected_type>(
1490 std::move( it ), value );
1494 struct missing_required_mapping_for {};
1498 template<
typename Name>
1499 [[noreturn]] DAW_ATTRIB_NOINLINE
void missing_required_mapping_error( ) {
1500#if defined( DAW_USE_EXCEPTIONS )
1501 throw missing_required_mapping_for<Name>{ };
1507 template<
typename,
typename...>
1508 struct find_names_in_pack;
1510 template<
typename Needle,
typename... Haystack>
1511 struct find_names_in_pack<Needle,
daw::fwd_pack<Haystack...>> {
1513 static constexpr daw::simple_array<daw::string_view,
1514 sizeof...( Haystack )>
1515 names = { Haystack::name... };
1516 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1517 "Name must exist" );
1520 static DAW_CONSTEVAL std::size_t find_position( ) {
1522 for( ;
n <
sizeof...( Haystack ); ++
n ) {
1523 if( Needle::name == names[n] ) {
1527 if( n >=
sizeof...( Haystack ) ) {
1528 missing_required_mapping_error<Needle>( );
1533 static constexpr std::size_t value = find_position( );
1536 template<
typename Needle,
typename... Haystack>
1537 inline static constexpr std::size_t find_names_in_pack_v =
1538 find_names_in_pack<Needle, Haystack...>::value;
1540 template<std::size_t pos,
typename JsonMember,
typename NamePack,
1542 typename TpArgs,
typename Value,
typename VisitedMembers>
1543 static constexpr void dependent_member_to_json_str(
1545 serialization_policy<WriteableType, SerializationOptions> it,
1546 TpArgs
const &args, Value
const &v, VisitedMembers &visited_members ) {
1547 if constexpr( not has_dependent_member_v<JsonMember> ) {
1552 (void)visited_members;
1555 using base_member_t =
typename daw::conditional_t<
1556 is_json_nullable_v<JsonMember>,
1557 ident_trait<json_nullable_member_type_t, JsonMember>,
1558 daw::traits::identity<JsonMember>>::type;
1560 using dependent_member = dependent_member_t<base_member_t>;
1564 static_assert( is_a_json_type_v<JsonMember>,
1565 "Unsupported data type" );
1566 if constexpr( is_json_nullable_v<JsonMember> ) {
1567 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1569 if( not get<pos>( args ) ) {
1574 if( daw::algorithm::contains( std::data( visited_members ),
1575 daw::data_end( visited_members ),
1576 dependent_member::name ) ) {
1580 visited_members.push_back( dependent_member::name );
1581 if( not is_first ) {
1586 it.write(
'"', dependent_member::name,
"\":", it.space );
1588 if constexpr( has_switcher_v<base_member_t> ) {
1589 it = member_to_string<dependent_member>(
1590 it,
typename base_member_t::switcher{ }( v ) );
1593 daw::constant<find_names_in_pack_v<dependent_member, NamePack>>;
1595 member_to_string<dependent_member>( it, get<idx::value>( args ) );
1601 template<std::size_t pos,
typename JsonMember,
typename WriteableType,
1603 typename Value,
typename Visited>
1604 static constexpr void to_json_str(
1606 serialization_policy<WriteableType, SerializationOptions> &it,
1607 Tuple
const &tp, Value
const &, Visited &visited_members ) {
1608 DAW_CPP23_STATIC_LOCAL
constexpr auto json_member_name =
1609 daw::string_view( std::data( JsonMember::name ),
1610 std::size( JsonMember::name ) );
1611 if( daw::algorithm::contains( std::data( visited_members ),
1612 daw::data_end( visited_members ),
1613 json_member_name ) ) {
1616 visited_members.push_back( json_member_name );
1617 static_assert( is_a_json_type_v<JsonMember>,
"Unsupported data type" );
1618 if constexpr( is_json_nullable_v<JsonMember> ) {
1619 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1620 if( not concepts::nullable_value_has_value( get<pos>( tp ) ) ) {
1623 if constexpr( has_null_checker_v<JsonMember> ) {
1624 if(
typename JsonMember::is_null_checker{ }( get<pos>( tp ) ) ) {
1630 if( not is_first ) {
1635 it.write(
'"', JsonMember::name,
"\":", it.space );
1637 it = member_to_string<JsonMember>( std::move( it ), get<pos>( tp ) );
1640 template<std::size_t TupleIdx,
typename JsonMember,
1642 template<
class...>
class Tuple,
typename... Args>
1643 static constexpr void to_json_ordered_str(
1644 std::size_t &array_idx, std::size_t array_size,
1645 serialization_policy<WriteableType, SerializerOptions> &it,
1646 Tuple<Args...>
const &tp ) {
1648 using json_member_type = ordered_member_subtype_t<JsonMember>;
1649 static_assert( is_a_json_type_v<json_member_type>,
1650 "Unsupported data type" );
1654 not is_a_json_tagged_variant_v<json_member_type>,
1655 "JSON tagged variant types are not supported when inside an array "
1656 "as an ordered structure" );
1658 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1659 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1661 it.write(
"null," );
1665 it = member_to_string<json_member_type>( it, get<TupleIdx>( tp ) );
1667 if( array_idx < array_size ) {
1706 template<options::FPOutputFormat fp_output_format,
unsigned Precision,
1707 typename Real,
typename WriteableType>
1708 constexpr WriteableType to_chars( Real
const &value,
1709 WriteableType out_it ) {
1710 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
1711 daw::jkj::dragonbox::to_decimal(
1712 value, daw::jkj::dragonbox::policy::sign::ignore );
1713 auto const original_digits =
1714 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1717 daw::max_digits10<Real> < daw::digits10<std::uintmax_t>,
1718 "The integer pow10 table must cover every Dragonbox significand "
1720 unsigned decimal_places = 0;
1721 unsigned scientific_places = 0;
1725 auto round_significand = [&](
unsigned digits )
constexpr {
1729 if( original_digits <= digits ) {
1732 auto const remove = original_digits - digits;
1733 using carrier_t =
decltype( dec.significand );
1734 auto const divisor =
1735 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
1736 auto quotient = dec.significand / divisor;
1737 auto const remainder = dec.significand % divisor;
1738 auto const halfway = divisor / 2;
1739 if( remainder > halfway or
1740 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
1743 dec.significand = quotient;
1744 dec.exponent +=
static_cast<int>( remove );
1745 if( daw::jkj::dragonbox::to_chars_detail::decimal_length(
1746 dec.significand ) > digits ) {
1748 dec.significand /= 10;
1752 if constexpr( Precision != daw::max_value<unsigned> ) {
1753 if constexpr( fp_output_format == options::FPOutputFormat::Auto ) {
1756 round_significand( Precision );
1757 }
else if constexpr( fp_output_format ==
1758 options::FPOutputFormat::Decimal ) {
1760 decimal_places = Precision;
1761 if( dec.exponent < -
static_cast<int>( Precision ) ) {
1762 using carrier_t =
decltype( dec.significand );
1763 auto const remove =
static_cast<unsigned>(
1764 -
static_cast<long long>( dec.exponent ) - Precision );
1765 if( remove > original_digits ) {
1770 dec.significand = 0;
1772 auto const divisor =
1773 static_cast<carrier_t
>( daw::cxmath::pow10( remove ) );
1774 auto quotient = dec.significand / divisor;
1775 auto const remainder = dec.significand % divisor;
1776 auto const halfway = divisor / 2;
1777 if( remainder > halfway or
1778 ( remainder == halfway and ( quotient & 1U ) != 0U ) ) {
1781 dec.significand = quotient;
1783 dec.exponent = -
static_cast<int>( Precision );
1785 }
else if constexpr( fp_output_format ==
1786 options::FPOutputFormat::Scientific ) {
1788 scientific_places = Precision;
1789 round_significand( Precision + 1 );
1792 unsigned const wanted = Precision + 1;
1794 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1796 while( current < wanted and current < 19 ) {
1797 dec.significand *= 10;
1801 }
else if constexpr( fp_output_format ==
1802 options::FPOutputFormat::Minimum ) {
1804 round_significand( Precision );
1807 auto const digit_values =
1808 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1812 static_cast<std::int32_t
>( digit_values ) + dec.exponent;
1814 auto const br = [&] {
1815 if constexpr( std::is_same_v<Real, float> ) {
1816 return daw::jkj::dragonbox::ieee754_bits( value );
1818 return daw::jkj::dragonbox::ieee754_bits(
1819 static_cast<double>( value ) );
1822 if( dec.significand == 0 ) {
1823 if( fp_output_format == options::FPOutputFormat::Decimal ) {
1825 if constexpr( Precision != daw::max_value<unsigned> ) {
1826 if( decimal_places != 0 ) {
1828 for(
unsigned n = 0;
n < decimal_places; ++
n ) {
1833 out_it.write(
".0" );
1840 if( br.is_negative( ) ) {
1843 if constexpr( fp_output_format ==
1844 options::FPOutputFormat::Scientific ) {
1847 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1848 dec, ptr, digit_values );
1849 if( scientific_places == 0 ) {
1850 out_it.copy_buffer( buff, ptr );
1852 char const *epos = buff;
1853 while( epos != ptr and *epos !=
'e' ) {
1856 char const *dot = buff;
1857 while( dot != epos and *dot !=
'.' ) {
1861 out_it.copy_buffer( buff, epos );
1864 out_it.copy_buffer( buff, dot + 1 );
1865 out_it.copy_buffer( dot + 1, epos );
1868 dot == epos ? 0U :
static_cast<unsigned>( epos - dot - 1 );
1869 while( count < scientific_places ) {
1873 out_it.copy_buffer( epos, ptr );
1876 }
else if constexpr( fp_output_format ==
1877 options::FPOutputFormat::Auto ) {
1878 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
1881 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1882 dec, ptr, digit_values );
1883 out_it.copy_buffer( buff, ptr );
1887 if( dec.exponent < 0 ) {
1888 if( whole_dig < 0 ) {
1889 out_it.write(
"0." );
1893 }
while( whole_dig < 0 );
1894 out_it = utils::integer_to_string( out_it, dec.significand );
1895 if constexpr( Precision != daw::max_value<unsigned> ) {
1896 for(
auto n =
static_cast<unsigned>( -dec.exponent );
1906 daw::cxmath::pow10(
static_cast<std::size_t
>( -dec.exponent ) );
1907 auto const p1val = dec.significand / p1pow;
1908 out_it = utils::integer_to_string( out_it, p1val );
1913 auto const p2val = dec.significand - ( p1val * p1pow );
1916 auto const l10_p1val = daw::cxmath::count_digits( p1val );
1917 auto const l10_p2val = daw::cxmath::count_digits( p2val );
1918 auto const extra_zeros =
1919 static_cast<int>( digit_values ) - ( l10_p2val + l10_p1val );
1920 for(
int n = 0;
n < extra_zeros; ++
n ) {
1924 out_it = utils::integer_to_string( out_it, p2val );
1925 if constexpr( Precision != daw::max_value<unsigned> ) {
1926 for(
auto n =
static_cast<unsigned>( -dec.exponent );
1934 out_it = utils::integer_to_string( out_it, dec.significand );
1936 while( dec.exponent > 0 ) {
1940 if( fp_output_format == options::FPOutputFormat::Decimal ) {
1941 if constexpr( Precision == daw::max_value<unsigned> ) {
1945 if( decimal_places != 0 ) {
1947 for(
unsigned n = 0;
n < decimal_places; ++
n ) {