DAW JSON Link
to_daw_json_string.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
11#include "version.h"
12
13#include "daw_json_assert.h"
17#include "daw_json_value.h"
18
19#include <daw/daw_algorithm.h>
20#include <daw/daw_arith_traits.h>
21#include <daw/daw_cpp_feature_check.h>
22#include <daw/daw_cxmath.h>
23#include <daw/daw_likely.h>
24#include <daw/daw_move.h>
25#include <daw/daw_traits.h>
26#include <daw/daw_utility.h>
27#include <daw/daw_visit.h>
28#include <daw/utf8/unchecked.h>
29
30#include <array>
31#include <ciso646>
32#include <daw/third_party/dragonbox/dragonbox.h>
33#include <optional>
34#include <sstream>
35#include <string>
36#include <tuple>
37#include <type_traits>
38#include <variant>
39
40namespace daw::json {
41 inline namespace DAW_JSON_VER {
42 namespace json_details {
43 template<FPOutputFormat fp_output_format, typename OutputIterator,
44 typename Real>
45 constexpr OutputIterator to_chars( Real const &value,
46 OutputIterator out_it );
47 } // namespace json_details
48
49 namespace json_details::to_strings {
50 using std::to_string;
51 // Need to use ADL to_string in unevaluated contexts. Limiting to it's
52 // own namespace
53 template<typename T>
54 [[nodiscard, maybe_unused]] constexpr auto
55 to_string( std::optional<T> const &v ) -> decltype( to_string( *v ) ) {
56 if( not has_value( v ) ) {
57 return { "null" };
58 }
59 return to_string( *v );
60 }
61
62 namespace to_string_test {
63 template<typename T>
64 [[maybe_unused]] auto to_string_test( T &&v )
65 -> decltype( to_string( DAW_FWD2( T, v ) ) );
66
67 template<typename T>
69 decltype( to_string_test( std::declval<T>( ) ) );
70 } // namespace to_string_test
71
72 template<typename T>
74 daw::is_detected<to_string_test::to_string_result, T>;
75
76 template<typename T>
78
79 } // namespace json_details::to_strings
80 namespace json_details {
81 template<typename T>
82 using from_string_test = decltype( from_string(
83 std::declval<daw::tag_t<T>>( ), std::declval<std::string_view>( ) ) );
84
85 template<typename T>
86 inline constexpr bool has_from_string_v =
87 daw::is_detected_v<from_string_test, T>;
88
89 template<typename T, typename U>
90 using has_lshift_test = decltype( operator<<(
91 std::declval<T &>( ), std::declval<U const &>( ) ) );
92
93 template<typename T, typename U>
94 using has_rshift_test = decltype( operator>>(
95 std::declval<T &>( ), std::declval<U const &>( ) ) );
96
97 template<typename T>
98 inline constexpr bool has_ostream_op_v =
99 daw::is_detected_v<has_lshift_test, std::stringstream, T>;
100
101 template<typename T>
102 inline constexpr bool has_istream_op_v =
103 daw::is_detected_v<has_rshift_test, std::stringstream, T>;
104
105 } // namespace json_details
106
107 /***
108 * This is the default ToJsonConverter for json_custom. By default is will
109 * return the stringified version of the value if, to_string( T ) exists.
110 * Otherwise it will fallback to an std::ostream converter for T if it
111 * exists.
112 * @tparam T type of value to convert to a string
113 */
114 template<typename T>
116 template<typename U>
117 [[nodiscard]] static inline auto use_stream( U const &v ) {
118 std::stringstream ss{ };
119 ss << v;
120 return DAW_MOVE( ss ).str( );
121 }
122
123 template<typename U>
124 [[nodiscard]] inline constexpr auto operator( )( U const &value ) const {
125 if constexpr( json_details::is_string_view_like_v<U> ) {
126 return std::string_view( std::data( value ), std::size( value ) );
127 } else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
129 return to_string( value );
130 } else if constexpr( json_details::has_ostream_op_v<U> ) {
131 return use_stream( value );
132 } else if constexpr( std::is_convertible_v<U, std::string_view> ) {
133 return static_cast<std::string_view>( value );
134 } else if constexpr( std::is_convertible_v<U, std::string> ) {
135 return static_cast<std::string>( value );
136 } else if constexpr( daw::is_arithmetic_v<U> ) {
137 return to_string( value );
138 } else if constexpr( std::is_enum_v<U> ) {
139 return to_string( static_cast<std::underlying_type_t<U>>( value ) );
140 } else if constexpr( json_details::is_dereferenceable_v<U> ) {
141 static_assert( json_details::has_op_bool_v<U>,
142 "default_to_converter cannot work with type" );
143 using dereferenced_type = json_details::dereferenced_t<U>;
145 dereferenced_type> ) {
146 if( value ) {
147 auto const &v = *value;
148 return std::string_view( std::data( v ), std::size( v ) );
149 }
150 return std::string_view( "null", 4 );
152 dereferenced_type> ) {
153 if( value ) {
155 return to_string( *value );
156 } else {
157 using result_t = DAW_TYPEOF( to_string( *value ) );
158 return result_t{ "null" };
159 }
160 } else if constexpr( std::is_convertible_v<dereferenced_type,
161 std::string_view> ) {
162 if( value ) {
163 return static_cast<std::string_view>( value );
164 }
165 return std::string_view{ "null" };
166 } else if constexpr( std::is_convertible_v<dereferenced_type,
167 std::string> ) {
168 if( value ) {
169 return static_cast<std::string>( value );
170 }
171 return std::string( "null" );
172 } else {
173 if( value ) {
174 return use_stream( *value );
175 } else {
176 return std::string( "null" );
177 }
178 }
179 }
180 }
181 };
182
183 namespace from_json_conv_details {
184 template<typename T>
185 [[nodiscard]] inline auto use_stream( std::string_view sv ) {
186 std::stringstream ss{ };
187 ss << sv;
188 T result;
189 ss >> result;
190 return result;
191 }
192 } // namespace from_json_conv_details
193
194 template<typename T>
196 [[nodiscard]] inline constexpr decltype( auto )
197 operator( )( std::string_view sv ) const {
198 if constexpr( std::disjunction<
199 std::is_same<T, std::string_view>,
200 std::is_same<T, std::optional<std::string_view>>>::
201 value ) {
202 return sv;
203 } else if constexpr( json_details::has_from_string_v<T> ) {
204 return from_string( daw::tag<T>, sv );
205 } else if constexpr( std::is_convertible_v<std::string_view, T> ) {
206 return static_cast<T>( sv );
207 } else if constexpr( std::is_convertible_v<std::string, T> ) {
208 return static_cast<T>( static_cast<std::string>( sv ) );
209 } else {
210 static_assert( json_details::has_istream_op_v<T>,
211 "Unsupported type in default to converter. Must "
212 "supply a custom one" );
213 static_assert( std::is_default_constructible_v<T>,
214 "Unsupported type in default to converter. Must "
215 "supply a custom one" );
216 return from_json_conv_details::use_stream<T>( sv );
217 }
218 }
219 };
220
221 namespace json_details {
222 template<typename JsonMember, typename OutputIterator,
223 typename parse_to_t>
224 [[nodiscard]] inline OutputIterator constexpr to_daw_json_string(
225 ParseTag<JsonParseTypes::Null>, OutputIterator it,
226 parse_to_t const &value );
227
228 template<typename JsonMember, typename OutputIterator,
229 json_options_t SerializationOptions, typename parse_to_t>
230 [[nodiscard]] constexpr serialization_policy<OutputIterator,
231 SerializationOptions>
235 parse_to_t const &value );
236
237 template<typename JsonMember, typename OutputIterator,
238 typename parse_to_t>
239 [[nodiscard]] constexpr OutputIterator
241 OutputIterator it, parse_to_t const &value );
242
243 template<typename JsonMember, typename OutputIterator,
244 json_options_t SerializationOptions, typename parse_to_t>
245 [[nodiscard]] constexpr serialization_policy<OutputIterator,
246 SerializationOptions>
250 parse_to_t const &value );
251
252 template<typename JsonMember, typename OutputIterator,
253 json_options_t SerializationOptions, typename parse_to_t>
254 [[nodiscard]] constexpr serialization_policy<OutputIterator,
255 SerializationOptions>
259 parse_to_t const &value );
260
261 template<typename JsonMember, typename OutputIterator,
262 typename parse_to_t>
263 [[nodiscard]] constexpr OutputIterator
265 parse_to_t const &value );
266
267 template<typename JsonMember, typename OutputIterator,
268 typename parse_to_t>
269 [[nodiscard]] constexpr OutputIterator
271 parse_to_t const &value );
272
273 template<typename JsonMember, typename OutputIterator,
274 typename parse_to_t>
275 [[nodiscard]] constexpr OutputIterator
277 parse_to_t const &value );
278
279 template<typename JsonMember, typename OutputIterator,
280 typename parse_to_t>
281 [[nodiscard]] constexpr OutputIterator
283 parse_to_t const &value );
284
285 template<typename JsonMember, typename OutputIterator,
286 typename parse_to_t>
287 [[nodiscard]] constexpr OutputIterator
289 parse_to_t const &value );
290
291 template<typename JsonMember, typename OutputIterator,
292 typename parse_to_t>
293 [[nodiscard]] constexpr OutputIterator
295 parse_to_t const &value );
296
297 template<typename JsonMember, typename OutputIterator,
298 typename parse_to_t>
299 [[nodiscard]] constexpr OutputIterator
301 OutputIterator it, parse_to_t const &value );
302
303 template<typename JsonMember, typename OutputIterator,
304 typename parse_to_t>
305 [[nodiscard]] constexpr OutputIterator
307 OutputIterator it, parse_to_t const &value );
308
309 template<typename JsonMember, typename OutputIterator,
310 typename parse_to_t>
311 [[nodiscard]] constexpr OutputIterator
313 parse_to_t const &value );
314
315 template<typename JsonMember, typename OutputIterator,
316 typename parse_to_t>
317 [[nodiscard]] constexpr OutputIterator
319 parse_to_t const &value );
320
321 template<typename Char>
322 constexpr char to_nibble_char( Char c ) {
323 auto const u = static_cast<unsigned>( static_cast<unsigned char>( c ) );
324 daw_json_assert( u < 16, ErrorReason::InvalidUTFEscape );
325 if( u < 10 ) {
326 return static_cast<char>( u + static_cast<unsigned char>( '0' ) );
327 } else {
328 return static_cast<char>( ( u - 10U ) +
329 static_cast<unsigned char>( 'A' ) );
330 }
331 }
332
333 template<typename OutputIterator>
334 constexpr OutputIterator output_hex( std::uint16_t c,
335 OutputIterator it ) {
336 char const nibbles[] = { '\\',
337 'u',
338 to_nibble_char( ( c >> 12U ) & 0xFU ),
339 to_nibble_char( ( c >> 8U ) & 0xFU ),
340 to_nibble_char( ( c >> 4U ) & 0xFU ),
341 to_nibble_char( c & 0xFU ) };
342
343 *it++ = nibbles[0];
344 *it++ = nibbles[1];
345 *it++ = nibbles[2];
346 *it++ = nibbles[3];
347 *it++ = nibbles[4];
348 *it++ = nibbles[5];
349 return it;
350 }
351
352 template<typename OutputIterator>
353 constexpr void utf32_to_utf8( std::uint32_t cp, OutputIterator &it ) {
354 if( cp <= 0x7FU ) {
355 *it++ = static_cast<char>( cp );
356 return;
357 }
358 if( cp <= 0x7FFU ) {
359 *it++ = static_cast<char>( ( cp >> 6U ) | 0b11000000U );
360 *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
361 return;
362 }
363 if( cp <= 0xFFFFU ) {
364 *it++ = static_cast<char>( ( cp >> 12U ) | 0b11100000U );
365 *it++ =
366 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U );
367 *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
368 return;
369 }
370 if( cp <= 0x10FFFFU ) {
371 *it++ = static_cast<char>( ( cp >> 18U ) | 0b11110000U );
372 *it++ =
373 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U );
374 *it++ =
375 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U );
376 *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
377 return;
378 }
379 daw_json_error( ErrorReason::InvalidUTFCodepoint );
380 }
381 } // namespace json_details
382
383 namespace utils {
384 template<bool do_escape = false,
386 typename OutputIterator, typename Container,
387 std::enable_if_t<
388 traits::is_container_like_v<daw::remove_cvref_t<Container>>,
389 std::nullptr_t> = nullptr>
390 [[nodiscard]] constexpr OutputIterator
391 copy_to_iterator( OutputIterator it, Container const &container ) {
392 constexpr bool restrict_high =
393 EightBitMode != EightBitModes::AllowFull or
394 ( OutputIterator::restricted_string_output ==
396 if constexpr( do_escape ) {
397 using iter = DAW_TYPEOF( std::begin( container ) );
398 using it_t = utf8::unchecked::iterator<iter>;
399 auto first = it_t( std::begin( container ) );
400 auto const last = it_t( std::end( container ) );
401 while( first != last ) {
402 auto const cp = *first++;
403 switch( cp ) {
404 case '"':
405 *it++ = '\\';
406 *it++ = '"';
407 break;
408 case '\\':
409 *it++ = '\\';
410 *it++ = '\\';
411 break;
412 case '\b':
413 *it++ = '\\';
414 *it++ = 'b';
415 break;
416 case '\f':
417 *it++ = '\\';
418 *it++ = 'f';
419 break;
420 case '\n':
421 *it++ = '\\';
422 *it++ = 'n';
423 break;
424 case '\r':
425 *it++ = '\\';
426 *it++ = 'r';
427 break;
428 case '\t':
429 *it++ = '\\';
430 *it++ = 't';
431 break;
432 default:
433 if( cp < 0x20U ) {
434 it = json_details::output_hex( static_cast<std::uint16_t>( cp ),
435 it );
436 break;
437 }
438 if constexpr( restrict_high ) {
439 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
441 static_cast<std::uint16_t>( cp ), it );
442 break;
443 }
444 if( cp > 0xFFFFU ) {
446 static_cast<std::uint16_t>( 0xD7C0U + ( cp >> 10U ) ), it );
448 static_cast<std::uint16_t>( 0xDC00U + ( cp & 0x3FFU ) ),
449 it );
450 break;
451 }
452 }
454 break;
455 }
456 }
457 } else {
458 for( auto c : container ) {
459 if constexpr( restrict_high ) {
460 daw_json_assert( ( static_cast<unsigned char>( c ) >= 0x20U and
461 static_cast<unsigned char>( c ) <= 0x7FU ),
462 ErrorReason::InvalidStringHighASCII );
463 }
464 *it++ = c;
465 }
466 }
467 return it;
468 }
469
470 template<bool do_escape = false,
472 typename OutputIterator>
473 [[nodiscard]] constexpr OutputIterator
474 copy_to_iterator( OutputIterator it, char const *ptr ) {
475 if( ptr == nullptr ) {
476 return it;
477 }
478 constexpr bool restrict_high =
479 EightBitMode != EightBitModes::AllowFull or
480 ( OutputIterator::restricted_string_output ==
482
483 if constexpr( do_escape ) {
484 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
485 while( *chr_it.base( ) != '\0' ) {
486 auto const cp = *chr_it++;
487 switch( cp ) {
488 case '"':
489 *it++ = '\\';
490 *it++ = '"';
491 break;
492 case '\\':
493 *it++ = '\\';
494 *it++ = '\\';
495 break;
496 case '\b':
497 *it++ = '\\';
498 *it++ = 'b';
499 break;
500 case '\f':
501 *it++ = '\\';
502 *it++ = 'f';
503 break;
504 case '\n':
505 *it++ = '\\';
506 *it++ = 'n';
507 break;
508 case '\r':
509 *it++ = '\\';
510 *it++ = 'r';
511 break;
512 case '\t':
513 *it++ = '\\';
514 *it++ = 't';
515 break;
516 default:
517 if( cp < 0x20U ) {
518 it = json_details::output_hex( static_cast<std::uint16_t>( cp ),
519 it );
520 break;
521 }
522 if constexpr( restrict_high ) {
523 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
525 static_cast<std::uint16_t>( cp ), it );
526 break;
527 }
528 if( cp > 0xFFFFU ) {
530 static_cast<std::uint16_t>( 0xD7C0U + ( cp >> 10U ) ), it );
531 it = output_hex(
532 static_cast<std::uint16_t>( 0xDC00U + ( cp & 0x3FFU ) ),
533 it );
534 break;
535 }
536 }
538 break;
539 }
540 }
541 } else {
542 while( *ptr != '\0' ) {
543 if constexpr( restrict_high ) {
544 daw_json_assert( ( static_cast<unsigned>( *ptr ) >= 0x20U and
545 static_cast<unsigned>( *ptr ) <= 0x7FU ),
546 ErrorReason::InvalidStringHighASCII );
547 }
548 *it++ = *ptr++;
549 }
550 }
551 return it;
552 }
553
554 template<bool do_escape = false,
556 typename OutputIterator, typename ParseState>
557 [[nodiscard]] constexpr OutputIterator
558 copy_to_iterator( OutputIterator it,
559 basic_json_value<ParseState> const &jv ) {
560 if( jv.is_null( ) ) {
561 return copy_to_iterator<do_escape, EightBitMode>( it, "null" );
562 } else {
563 return copy_to_iterator<do_escape, EightBitMode>(
564 it, jv.get_string_view( ) );
565 }
566 }
567 } // namespace utils
568
569 namespace json_details {
570 template<typename JsonMember, typename OutputIterator,
571 typename parse_to_t>
572 [[nodiscard]] constexpr OutputIterator
574 parse_to_t const &value ) {
575
576 if constexpr( JsonMember::literal_as_string ==
578 *it++ = '"';
579 }
580 if( value ) {
581 it = utils::copy_to_iterator( it, "true" );
582 } else {
583 it = utils::copy_to_iterator( it, "false" );
584 }
585 if constexpr( JsonMember::literal_as_string ==
587 *it++ = '"';
588 }
589 return it;
590 }
591
592 template<std::size_t idx, typename JsonMembers, typename OutputIterator,
593 typename parse_to_t>
594 constexpr void to_variant_string( OutputIterator &it,
595 parse_to_t const &value ) {
596 if constexpr( idx < std::variant_size<parse_to_t>::value ) {
597 if( value.index( ) != idx ) {
598 to_variant_string<idx + 1, JsonMembers>( it, value );
599 return;
600 }
601 using element_t = typename JsonMembers::json_elements;
602 using JsonMember =
603 typename pack_element<idx, typename element_t::element_map_t>::type;
604 it = to_daw_json_string<JsonMember>(
606 daw::get_nt<idx>( value ) );
607 }
608 }
609
610 template<typename JsonMember, typename OutputIterator,
611 typename parse_to_t>
612 [[nodiscard]] inline constexpr OutputIterator
614 parse_to_t const &value ) {
615
616 assert( value.index( ) >= 0 );
617 to_variant_string<0, JsonMember>( it, value );
618 return it;
619 }
620
621 template<typename JsonMember, typename OutputIterator,
622 typename parse_to_t>
623 [[nodiscard]] inline constexpr OutputIterator
625 OutputIterator it, parse_to_t const &value ) {
626
627 to_variant_string<0, JsonMember>( it, value );
628 return it;
629 }
630
631 template<typename JsonMember, typename OutputIterator,
632 typename parse_to_t>
633 [[nodiscard]] inline constexpr OutputIterator
635 OutputIterator it, parse_to_t const &value ) {
636
637 to_variant_string<0, JsonMember>( it, value );
638 return it;
639 }
640
641 template<typename JsonMember, typename OutputIterator, typename Optional>
642 [[nodiscard]] inline constexpr OutputIterator
644 Optional const &value ) {
645 static_assert( is_dereferenceable_v<Optional> );
646
647 if( not json_details::has_value( value ) ) {
648 return utils::copy_to_iterator( it, "null" );
649 }
651 if constexpr( json_details::has_op_star_v<Optional> ) {
652 return to_daw_json_string<JsonMember>( tag_type{ }, it, *value );
653 } else {
654 return to_daw_json_string<JsonMember>( tag_type{ }, it, value );
655 }
656 }
657
658 template<typename JsonMember, typename OutputIterator,
659 typename parse_to_t>
660 [[nodiscard]] constexpr OutputIterator
662 parse_to_t const &value ) {
663
664 static_assert(
665 std::is_convertible<parse_to_t,
666 typename JsonMember::parse_to_t>::value,
667 "value must be convertible to specified type in class contract" );
668
669 if constexpr( std::is_floating_point<
670 typename JsonMember::parse_to_t>::value ) {
671 if( daw::cxmath::is_nan( value ) ) {
672 if constexpr( JsonMember::literal_as_string ==
674 JsonMember::allow_number_errors ==
676 JsonMember::allow_number_errors ==
678 daw_json_error( ErrorReason::NumberIsNaN );
679 } else {
680 *it++ = '"';
681 it = utils::copy_to_iterator( it, "NaN" );
682 *it++ = '"';
683 return it;
684 }
685 } else if( daw::cxmath::is_inf( value ) ) {
686 if constexpr( JsonMember::literal_as_string ==
688 JsonMember::allow_number_errors ==
690 JsonMember::allow_number_errors ==
692 daw_json_error( ErrorReason::NumberIsInf );
693 } else {
694 *it++ = '"';
695 if( value < 0 ) {
696 *it++ = '-';
697 }
698 it = utils::copy_to_iterator( it, "Infinity" );
699 *it++ = '"';
700 return it;
701 }
702 }
703 }
704
705 if constexpr( JsonMember::literal_as_string ==
707 *it++ = '"';
708 }
709 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
710 static_assert( sizeof( parse_to_t ) <= sizeof( double ) );
711 if constexpr( it.is_pointer ) {
712 it.set(
713 to_chars<JsonMember::fp_output_format>( value, it.get( ) ) );
714 } else {
715 char buff[50]{ };
716 buff[49] = 0;
717 char *ptr = buff;
718 ptr = to_chars<JsonMember::fp_output_format>( value, ptr );
719 std::copy( buff, ptr, it );
720 }
721 } else {
722 using std::to_string;
724 it = utils::copy_to_iterator( it, to_string( value ) );
725 }
726 if constexpr( JsonMember::literal_as_string ==
728 *it++ = '"';
729 }
730 return it;
731 }
732
733 template<typename T>
734 using base_int_type_impl = std::underlying_type<T>;
735
736 template<typename T>
738 typename std::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
739 daw::traits::identity<T>>::type;
740
741 inline constexpr auto digits100 = [] {
742 std::array<char[2], 100> result{ };
743 for( size_t n = 0; n < 100; ++n ) {
744 result[n][0] =
745 static_cast<char>( ( n % 10 ) + static_cast<unsigned char>( '0' ) );
746 result[n][1] =
747 static_cast<char>( ( n / 10 ) + static_cast<unsigned char>( '0' ) );
748 }
749 return result;
750 }( );
751
752 template<typename JsonMember, typename OutputIterator,
753 typename parse_to_t>
754 [[nodiscard]] constexpr OutputIterator
756 parse_to_t const &value ) {
757
758 static_assert(
759 std::is_convertible<parse_to_t,
760 typename JsonMember::parse_to_t>::value,
761 "value must be convertible to specified type in class contract" );
762
763 using std::to_string;
765 using under_type = base_int_type_t<parse_to_t>;
766
767 if constexpr( JsonMember::literal_as_string ==
769 *it++ = '"';
770 }
771 if constexpr( std::disjunction<std::is_enum<parse_to_t>,
772 daw::is_integral<parse_to_t>>::value ) {
773 auto v = static_cast<under_type>( value );
774
775 char buff[daw::numeric_limits<under_type>::digits10 + 1]{ };
776 char *ptr = buff;
777 if( v < 0 ) {
778 *it++ = '-';
779 // Do 1 round here just in case we are
780 // daw::numeric_limits<intmax_t>::min( ) and cannot negate
781 // This is a subtraction because v < 0 % 10 is negative
782 *ptr++ = static_cast<char>( '0' - static_cast<char>( v % 10 ) );
783 v /= -10;
784 if( v == 0 ) {
785 *it++ = buff[0];
786 if constexpr( JsonMember::literal_as_string ==
788 *it++ = '"';
789 }
790 return it;
791 }
792 }
793 if( v == 0 ) {
794 *ptr++ = '0';
795 }
796 while( v >= 10 ) {
797 auto const tmp = static_cast<std::size_t>( v % 100 );
798 v /= 100;
799 ptr[0] = digits100[tmp][0];
800 ptr[1] = digits100[tmp][1];
801 ptr += 2;
802 }
803 if( v > 0 ) {
804 *ptr++ = static_cast<char>( '0' + static_cast<char>( v ) );
805 }
806 --ptr;
807 *it++ = *ptr;
808 while( ptr != buff ) {
809 --ptr;
810 *it++ = *ptr;
811 }
812 } else {
813 // Fallback to ADL
814 it = utils::copy_to_iterator( it, to_string( value ) );
815 }
816 if constexpr( JsonMember::literal_as_string ==
818 *it++ = '"';
819 }
820 return it;
821 }
822
823 template<typename JsonMember, typename OutputIterator,
824 typename parse_to_t>
825 [[nodiscard]] constexpr OutputIterator
827 parse_to_t const &value ) {
828
829 static_assert(
830 std::is_convertible<parse_to_t,
831 typename JsonMember::parse_to_t>::value,
832 "value must be convertible to specified type in class contract" );
833
834 using std::to_string;
836 using under_type = base_int_type_t<parse_to_t>;
837
838 if constexpr( JsonMember::literal_as_string ==
840 *it++ = '"';
841 }
842 if constexpr( std::disjunction<std::is_enum<parse_to_t>,
843 daw::is_integral<parse_to_t>>::value ) {
844 auto v = static_cast<under_type>( value );
845
846 if( DAW_UNLIKELY( v == 0 ) ) {
847 *it++ = '0';
848 } else {
849 daw_json_assert( v > 0, ErrorReason::NumberOutOfRange );
850 char buff[daw::numeric_limits<under_type>::digits10 + 1]{ };
851 char *ptr = buff;
852 while( v >= 10 ) {
853 auto const tmp = static_cast<std::size_t>( v % 100 );
854 v /= 100;
855 ptr[0] = digits100[tmp][0];
856 ptr[1] = digits100[tmp][1];
857 ptr += 2;
858 }
859 if( v > 0 ) {
860 *ptr++ = static_cast<char>( '0' + static_cast<char>( v ) );
861 }
862 --ptr;
863 *it++ = *ptr;
864 while( ptr != buff ) {
865 --ptr;
866 *it++ = *ptr;
867 }
868 }
869 } else {
870 // Fallback to ADL
871 it = utils::copy_to_iterator( it, to_string( value ) );
872 }
873 if constexpr( JsonMember::literal_as_string ==
875 *it++ = '"';
876 }
877 return it;
878 }
879 } // namespace json_details
880
881 namespace utils {
882 namespace utils_details {
883 template<typename Integer>
884 struct number {
885 using parse_to_t = Integer;
888 };
889 } // namespace utils_details
890
891 template<typename Integer, typename OutputIterator>
892 inline constexpr OutputIterator
893 integer_to_string( OutputIterator it, Integer const &value ) {
894 static_assert( daw::is_integral_v<Integer> );
895
896 if constexpr( daw::is_unsigned_v<Integer> ) {
900 } else {
904 }
905 }
906 } // namespace utils
907
908 namespace json_details {
909 template<typename JsonMember, typename OutputIterator,
910 typename parse_to_t>
911 [[nodiscard]] inline constexpr OutputIterator
913 OutputIterator it, parse_to_t const &value ) {
914
915 static_assert(
916 std::is_convertible<parse_to_t,
917 typename JsonMember::parse_to_t>::value,
918 "Value must be convertible to specialized type in "
919 "json_data_contract" );
920
921 constexpr EightBitModes eight_bit_mode = JsonMember::eight_bit_mode;
922 *it++ = '"';
923 if( std::size( value ) > 0U ) {
924 it = utils::copy_to_iterator<false, eight_bit_mode>( it, value );
925 }
926 *it++ = '"';
927 return it;
928 }
929
930 template<typename JsonMember, typename OutputIterator,
931 typename parse_to_t>
932 [[nodiscard]] inline constexpr OutputIterator
934 OutputIterator it, parse_to_t const &value ) {
935
936 /* TODO is something like this necessary
937 static_assert(
938 std::is_convertible<parse_to_t, typename
939 JsonMember::parse_to_t>::value, "value must be convertible to
940 specified type in class contract" );
941 */
942
943 constexpr EightBitModes eight_bit_mode = JsonMember::eight_bit_mode;
944 *it++ = '"';
945 it = utils::copy_to_iterator<true, eight_bit_mode>( it, value );
946 *it++ = '"';
947 return it;
948 }
949
950 template<typename T>
951 [[nodiscard]] inline constexpr bool is_null( std::optional<T> const &v ) {
952 return not static_cast<bool>( v );
953 }
954
955 template<typename T>
956 [[nodiscard]] inline constexpr bool is_null( T const & ) {
957 return false;
958 }
959
960 template<typename JsonMember, typename OutputIterator,
961 typename parse_to_t>
962 [[nodiscard]] constexpr OutputIterator
964 parse_to_t const &value ) {
965
966 static_assert(
967 std::is_convertible<parse_to_t,
968 typename JsonMember::parse_to_t>::value,
969 "value must be convertible to specified type in class contract" );
970
972 // TODO: document customization point
973 if( is_null( value ) ) {
974 return utils::copy_to_iterator( it, "null" );
975 }
976 *it++ = '"';
977 datetime::ymdhms const civil = datetime::time_point_to_civil( value );
979 *it++ = '-';
980 if( civil.month < 10 ) {
981 *it++ = '0';
982 }
984 *it++ = '-';
985 if( civil.day < 10 ) {
986 *it++ = '0';
987 }
988 it = utils::integer_to_string( it, civil.day );
989 *it++ = 'T';
990 if( civil.hour < 10 ) {
991 *it++ = '0';
992 }
994 *it++ = ':';
995 if( civil.minute < 10 ) {
996 *it++ = '0';
997 }
999 *it++ = ':';
1000 if( civil.second < 10 ) {
1001 *it++ = '0';
1002 }
1004 if( civil.millisecond > 0 ) {
1005 *it++ = '.';
1007 }
1008 *it++ = 'Z';
1009 *it++ = '"';
1010 return it;
1011 }
1012
1013 template<typename JsonMember, typename OutputIterator,
1014 typename parse_to_t>
1015 [[nodiscard]] inline constexpr OutputIterator
1017 parse_to_t const &value ) {
1018
1019 return utils::copy_to_iterator( it, value );
1020 }
1021
1022 template<typename JsonMember, typename OutputIterator,
1023 typename parse_to_t>
1024 [[nodiscard]] inline constexpr OutputIterator
1026 parse_to_t const &value ) {
1027
1028 static_assert(
1029 std::is_convertible<parse_to_t,
1030 typename JsonMember::parse_to_t>::value,
1031 "value must be convertible to specified type in class contract" );
1032
1033 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
1036 } else if constexpr( is_json_map_alias_v<parse_to_t> ) {
1038 value );
1039 } else {
1040 static_assert( is_submember_tagged_variant_v<parse_to_t>,
1041 "Could not find appropriate mapping or to_json_data "
1042 "member of json_data_contract" );
1044 }
1045 }
1046
1047 template<typename JsonMember, typename OutputIterator,
1048 typename parse_to_t>
1049 [[nodiscard]] inline constexpr OutputIterator
1051 parse_to_t const &value ) {
1052
1053 static_assert(
1054 std::is_convertible<parse_to_t,
1055 typename JsonMember::parse_to_t>::value,
1056 "value must be convertible to specified type in class contract" );
1057
1058 if constexpr( JsonMember::custom_json_type !=
1060 *it++ = '"';
1061 if constexpr( std::is_invocable_r<
1062 OutputIterator, typename JsonMember::to_converter_t,
1063 OutputIterator, parse_to_t>::value ) {
1064
1065 it = typename JsonMember::to_converter_t{ }( it, value );
1066 } else {
1068 it, typename JsonMember::to_converter_t{ }( value ) );
1069 }
1070 *it++ = '"';
1071 return it;
1072 } else {
1074 it, typename JsonMember::to_converter_t{ }( value ) );
1075 }
1076 }
1077
1078 template<typename JsonMember, typename OutputIterator,
1079 json_options_t SerializationOptions, typename parse_to_t,
1080 std::size_t... Is>
1084 parse_to_t const &value, std::index_sequence<Is...> ) {
1085
1086 auto const to_daw_json_string_help = [&]( auto Idx ) {
1087 using index = daw::remove_cvref_t<decltype( Idx )>;
1088 using pack_element = tuple_elements_pack<parse_to_t>;
1089 using T = std::tuple_element_t<index::value,
1090 typename JsonMember::sub_member_list>;
1091
1092 it = to_daw_json_string<T>(
1094 pack_element::template get<index::value>( value ) );
1095 if constexpr( index::value + 1 < sizeof...( Is ) ) {
1096 *it++ = ',';
1097 it.next_member( );
1098 }
1099 };
1100 (void)to_daw_json_string_help;
1101
1102 daw::Empty const expander[]{
1103 ( to_daw_json_string_help( daw::constant<Is>{ } ), daw::Empty{ } )...,
1104 daw::Empty{} };
1105 (void)expander;
1106
1107 return it;
1108 }
1109
1110 template<typename JsonMember, typename OutputIterator,
1111 json_options_t SerializationOptions, typename parse_to_t>
1112 [[nodiscard]] constexpr serialization_policy<OutputIterator,
1113 SerializationOptions>
1117 parse_to_t const &value ) {
1118
1119 using tuple_t = typename JsonMember::parse_to_t;
1120 using element_pack = tuple_elements_pack<tuple_t>;
1121
1122 static_assert( is_tuple_v<tuple_t>, "Expected tuple like type" );
1123 static_assert(
1124 std::is_convertible<parse_to_t, tuple_t>::value,
1125 "value must be convertible to specified type in class contract" );
1126
1127 *it++ = '[';
1128 it.add_indent( );
1129 it.next_member( );
1130 it = to_daw_json_string_tuple<JsonMember>(
1131 it, value, std::make_index_sequence<element_pack::size>{ } );
1132 it.del_indent( );
1133 if constexpr( element_pack::size > 0 ) {
1134 if constexpr( element_pack::size > 0 and
1135 it.output_trailing_comma == OutputTrailingComma::Yes ) {
1136 *it++ = ',';
1137 }
1138 it.next_member( );
1139 }
1140 *it++ = ']';
1141 return it;
1142 }
1143
1144 template<typename JsonMember, typename OutputIterator,
1145 json_options_t SerializationOptions, typename parse_to_t>
1146 [[nodiscard]] constexpr serialization_policy<OutputIterator,
1147 SerializationOptions>
1151 parse_to_t const &value ) {
1152
1153 using array_t = typename JsonMember::parse_to_t;
1154 if constexpr( is_container_v<array_t> ) {
1155 static_assert(
1156 std::is_convertible<parse_to_t, array_t>::value,
1157 "value must be convertible to specified type in class contract" );
1158 } else {
1159 static_assert(
1161 "This is a special case for pointer like(T*, unique_ptr<T>, "
1162 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1163 "encode the size of the data with the pointer. Will take any "
1164 "Container like type, but std::span like types work too" );
1165 static_assert(
1166 is_container_v<parse_to_t>,
1167 "This is a special case for pointer like(T*, unique_ptr<T>, "
1168 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1169 "encode the size of the data with the pointer. Will take any "
1170 "Container like type, but std::span like types work too" );
1171 }
1172
1173 *it++ = '[';
1174 it.add_indent( );
1175 auto first = std::begin( value );
1176 auto last = std::end( value );
1177 bool const has_elements = first != last;
1178 while( first != last ) {
1179 it.next_member( );
1180 it = to_daw_json_string<typename JsonMember::json_element_t>(
1182 *first );
1183 ++first;
1184 if( first != last ) {
1185 *it++ = ',';
1186 }
1187 }
1188 it.del_indent( );
1189 if constexpr( it.output_trailing_comma == OutputTrailingComma::Yes ) {
1190 if( has_elements ) {
1191 *it++ = ',';
1192 }
1193 }
1194 if( has_elements ) {
1195 it.next_member( );
1196 }
1197 *it++ = ']';
1198 return it;
1199 }
1200
1201 template<typename JsonMember, typename OutputIterator,
1202 typename parse_to_t>
1203 [[nodiscard]] constexpr OutputIterator
1205 OutputIterator it, parse_to_t const &value ) {
1206 return to_daw_json_string<JsonMember>(
1208 }
1209
1210 template<typename Key, typename Value>
1211 [[maybe_unused]] inline constexpr Key const &
1212 json_get_key( std::pair<Key, Value> const &kv ) {
1213 return kv.first;
1214 }
1215
1216 template<typename Key, typename Value>
1217 [[maybe_unused]] inline constexpr Value const &
1218 json_get_value( std::pair<Key, Value> const &kv ) {
1219 return kv.second;
1220 }
1221
1222 template<typename JsonMember, typename OutputIterator,
1223 json_options_t SerializeOptions, typename parse_to_t>
1224 [[nodiscard]] constexpr serialization_policy<OutputIterator,
1225 SerializeOptions>
1229 parse_to_t const &value ) {
1230
1231 static_assert(
1232 std::is_convertible<parse_to_t,
1233 typename JsonMember::parse_to_t>::value,
1234 "value must be convertible to specified type in class contract" );
1235 using key_t = typename JsonMember::json_key_t;
1236 using value_t = typename JsonMember::json_value_t;
1237 *it++ = '[';
1238 it.add_indent( );
1239 auto first = std::begin( value );
1240 auto last = std::end( value );
1241 bool const has_elements = first != last;
1242 while( first != last ) {
1243 it.next_member( );
1244 *it++ = '{';
1245 it.add_indent( );
1246 it.next_member( );
1247 // Append Key Name
1248 *it++ = '"';
1249 it = utils::copy_to_iterator( it, key_t::name );
1250 *it++ = '"';
1251 *it++ = ':';
1252 it.output_space( );
1253 // Append Key Value
1254 it = to_daw_json_string<key_t>( ParseTag<key_t::expected_type>{ }, it,
1255 json_get_key( *first ) );
1256
1257 *it++ = ',';
1258 // Append Value Name
1259 it.next_member( );
1260 *it++ = '"';
1261 it = utils::copy_to_iterator( it, value_t::name );
1262 *it++ = '"';
1263 *it++ = ':';
1264 it.output_space( );
1265 // Append Value Value
1266 it = to_daw_json_string<value_t>( ParseTag<value_t::expected_type>{ },
1267 it, json_get_value( *first ) );
1268
1269 it.del_indent( );
1270 if constexpr( it.output_trailing_comma == OutputTrailingComma::Yes ) {
1271 if( has_elements ) {
1272 *it++ = ',';
1273 }
1274 }
1275 it.next_member( );
1276 *it++ = '}';
1277 ++first;
1278 if( first != last ) {
1279 *it++ = ',';
1280 }
1281 }
1282 it.del_indent( );
1283 if constexpr( it.output_trailing_comma == OutputTrailingComma::Yes ) {
1284 if( has_elements ) {
1285 *it++ = ',';
1286 }
1287 }
1288 if( has_elements ) {
1289 it.next_member( );
1290 }
1291 *it++ = ']';
1292 return it;
1293 }
1294
1295 template<typename JsonMember, typename OutputIterator,
1296 json_options_t SerializationOptions, typename parse_to_t>
1297 [[nodiscard]] constexpr serialization_policy<OutputIterator,
1298 SerializationOptions>
1302 parse_to_t const &value ) {
1303
1304 *it++ = '{';
1305 it.add_indent( );
1306 auto first = std::begin( value );
1307 auto last = std::end( value );
1308 bool const has_elements = first != last;
1309 while( first != last ) {
1310 auto const &v = *first;
1311 it.next_member( );
1312 it = to_daw_json_string<typename JsonMember::json_key_t>(
1314 json_get_key( v ) );
1315 *it++ = ':';
1316 it.output_space( );
1317 it = to_daw_json_string<typename JsonMember::json_element_t>(
1319 json_get_value( v ) );
1320 ++first;
1321 if( first != last ) {
1322 *it++ = ',';
1323 }
1324 }
1325 it.del_indent( );
1326 if constexpr( it.output_trailing_comma == OutputTrailingComma::Yes ) {
1327 if( has_elements ) {
1328 *it++ = ',';
1329 }
1330 }
1331 if( has_elements ) {
1332 it.next_member( );
1333 }
1334 *it++ = '}';
1335 return it;
1336 }
1337
1338 template<typename JsonMember, typename OutputIterator, typename T>
1339 [[nodiscard]] inline constexpr OutputIterator
1340 member_to_string( template_param<JsonMember>, OutputIterator it,
1341 T const &value ) {
1342 return to_daw_json_string<JsonMember>(
1343 ParseTag<JsonMember::expected_type>{ }, DAW_MOVE( it ), value );
1344 }
1345
1346 template<typename>
1348
1349 // This is only ever called in a constant expression. But will not compile
1350 // if exceptions are disabled and it tries to throw
1351 template<typename Name>
1353#ifdef DAW_USE_EXCEPTIONS
1355#else
1356 std::terminate( );
1357#endif
1358 }
1359
1360 template<typename, typename...>
1362
1363 template<typename Needle, typename... Haystack>
1364 struct find_names_in_pack<Needle, daw::fwd_pack<Haystack...>> {
1365
1366 static constexpr std::size_t find_position( ) {
1367 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1368 "Name must exist" );
1369 constexpr std::array const names = { Haystack::name... };
1370 std::size_t n = 0;
1371 for( ; n < sizeof...( Haystack ); ++n ) {
1372 if( Needle::name == names[n] ) {
1373 return n;
1374 }
1375 }
1376 if( n >= sizeof...( Haystack ) ) {
1377 missing_required_mapping_error<Needle>( );
1378 }
1379 DAW_UNREACHABLE( );
1380 }
1381
1382 static constexpr std::size_t value = find_position( );
1383 };
1384
1385 template<typename Needle, typename... Haystack>
1386 inline static constexpr std::size_t find_names_in_pack_v =
1387 find_names_in_pack<Needle, Haystack...>::value;
1388
1389 template<std::size_t, typename JsonMember, typename /*NamePack*/,
1390 typename OutputIterator, typename TpArgs, typename Value,
1391 typename VisitedMembers,
1392 std::enable_if_t<not has_dependent_member_v<JsonMember>,
1393 std::nullptr_t> = nullptr>
1394 DAW_ATTRIB_INLINE inline constexpr void
1395 dependent_member_to_json_str( bool &, OutputIterator const &,
1396 TpArgs const &, Value const &,
1397 VisitedMembers const & ) {
1398
1399 // This is empty so that the call is able to be put into a pack
1400 }
1401
1402 template<std::size_t pos, typename JsonMember, typename NamePack,
1403 typename OutputIterator, json_options_t SerializationOptions,
1404 typename TpArgs, typename Value, typename VisitedMembers,
1405 std::enable_if_t<has_dependent_member_v<JsonMember>,
1406 std::nullptr_t> = nullptr>
1408 bool &is_first,
1410 TpArgs const &args, Value const &v, VisitedMembers &visited_members ) {
1411 using dependent_member = dependent_member_t<JsonMember>;
1412 using daw::get;
1413 using std::get;
1414 static_assert( is_a_json_type<JsonMember>::value,
1415 "Unsupported data type" );
1416 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1417 // We have no requirement to output this member when it's null
1418 if( not get<pos>( args ) ) {
1419 return;
1420 }
1421 }
1422 if( daw::algorithm::contains( std::data( visited_members ),
1423 daw::data_end( visited_members ),
1424 dependent_member::name ) ) {
1425 // Already outputted this member
1426 return;
1427 }
1428 visited_members.push_back( dependent_member::name );
1429 if( not is_first ) {
1430 *it++ = ',';
1431 }
1432 it.next_member( );
1433 is_first = false;
1434 *it++ = '"';
1435 it = utils::copy_to_iterator<false, EightBitModes::AllowFull>(
1436 it, dependent_member::name );
1437 *it++ = '"';
1438 *it++ = ':';
1439 it.output_space( );
1440
1441 if constexpr( has_switcher_v<JsonMember> ) {
1442 it = member_to_string( template_arg<dependent_member>, it,
1443 typename JsonMember::switcher{ }( v ) );
1444 } else {
1445 constexpr auto idx = find_names_in_pack_v<dependent_member, NamePack>;
1446 it = member_to_string( template_arg<dependent_member>, it,
1447 get<idx>( args ) );
1448 }
1449 (void)it;
1450 }
1451
1452 template<std::size_t pos, typename JsonMember, typename OutputIterator,
1453 json_options_t SerializationOptions, typename Tuple,
1454 typename Value, typename Visited>
1455 inline constexpr void to_json_str(
1456 bool &is_first,
1458 Tuple const &tp, Value const &, Visited &visited_members ) {
1459 constexpr auto json_member_name = daw::string_view(
1460 std::data( JsonMember::name ), std::size( JsonMember::name ) );
1461 if( daw::algorithm::contains( std::data( visited_members ),
1462 daw::data_end( visited_members ),
1463 json_member_name ) ) {
1464 return;
1465 }
1466 visited_members.push_back( json_member_name );
1468 "Unsupported data type" );
1470 JsonMember::nullable == JsonNullable::Nullable ) {
1471 if( not json_details::has_value( get<pos>( tp ) ) ) {
1472 return;
1473 }
1474 }
1475 if( not is_first ) {
1476 *it++ = ',';
1477 }
1478 it.next_member( );
1479 is_first = false;
1480 *it++ = '"';
1481 it = utils::copy_to_iterator<false, EightBitModes::AllowFull>(
1482 it, JsonMember::name );
1483 *it++ = '"';
1484 *it++ = ':';
1485 it.output_space( );
1486 it = member_to_string( template_arg<JsonMember>, DAW_MOVE( it ),
1487 get<pos>( tp ) );
1488 }
1489
1490 template<size_t TupleIdx, typename JsonMember, typename OutputIterator,
1491 json_options_t SerializerOptions, template<class...> class Tuple,
1492 typename... Args>
1493 constexpr void to_json_ordered_str(
1494 std::size_t &array_idx, std::size_t array_size,
1496 Tuple<Args...> const &tp ) {
1497
1498 using json_member_type = ordered_member_subtype_t<JsonMember>;
1500 "Unsupported data type" );
1501 // json_tagged_variant like members cannot work as we have no member
1502 // names to work with
1503 static_assert(
1505 "JSON tagged variant types are not supported when inside an array "
1506 "as an ordered structure" );
1507
1508 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1509 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1510 it.next_member( );
1511 *it++ = 'n';
1512 *it++ = 'u';
1513 *it++ = 'l';
1514 *it++ = 'l';
1515 *it++ = ',';
1516 it.next_member( );
1517 }
1518 }
1519 it = member_to_string( template_arg<json_member_type>, it,
1520 get<TupleIdx>( tp ) );
1521 ++array_idx;
1522 if( array_idx < array_size ) {
1523 *it++ = ',';
1524 it.next_member( );
1525 }
1526 }
1527
1528 template<FPOutputFormat fp_output_fmt, typename OutputIterator,
1529 typename Real>
1530 constexpr OutputIterator to_chars( Real const &value,
1531 OutputIterator out_it ) {
1532 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
1533 daw::jkj::dragonbox::to_decimal(
1534 value, daw::jkj::dragonbox::policy::sign::ignore );
1535
1536 auto const digits =
1537 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1538 dec.significand );
1539
1540 auto whole_dig = static_cast<std::int32_t>( digits ) + dec.exponent;
1541
1542 auto const br = [&] {
1543 if constexpr( std::is_same_v<Real, float> ) {
1544 return daw::jkj::dragonbox::ieee754_bits( value );
1545 } else {
1546 return daw::jkj::dragonbox::ieee754_bits(
1547 static_cast<double>( value ) );
1548 }
1549 }( );
1550 if( dec.significand == 0 ) {
1551 if( br.is_negative( ) ) {
1552 *out_it++ = '-';
1553 }
1554 *out_it++ = '0';
1555 return out_it;
1556 }
1557 if constexpr( true and fp_output_fmt == FPOutputFormat::Scientific ) {
1559 digits );
1560 } else /*if constexpr( fp_output_fmt != FPOutputFormat::Decimal )*/ {
1561 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
1563 digits );
1564 }
1565 }
1566 if( br.is_negative( ) ) {
1567 *out_it++ = '-';
1568 }
1569 if( dec.significand == 0 ) {
1570 *out_it++ = '0';
1571 return out_it;
1572 }
1573 if( dec.exponent < 0 ) {
1574
1575 if( whole_dig < 0 ) {
1576 *out_it++ = '0';
1577 *out_it++ = '.';
1578 do {
1579 *out_it++ = '0';
1580 ++whole_dig;
1581 } while( whole_dig < 0 );
1582 out_it = utils::integer_to_string( out_it, dec.significand );
1583 return out_it;
1584 }
1585 // TODO allow for decimal output for all
1586 auto const p1pow =
1587 daw::cxmath::pow10( static_cast<std::size_t>( -dec.exponent ) );
1588 auto const p1val = dec.significand / p1pow;
1589 out_it = utils::integer_to_string( out_it, p1val );
1590 if( p1pow == 1 ) {
1591 return out_it;
1592 }
1593 *out_it++ = '.';
1594 auto const p2val = dec.significand - ( p1val * p1pow );
1595 out_it = utils::integer_to_string( out_it, p2val );
1596 return out_it;
1597 }
1598 out_it = utils::integer_to_string( out_it, dec.significand );
1599 while( dec.exponent > 0 ) {
1600 *out_it++ = '0';
1601 --dec.exponent;
1602 }
1603 return out_it;
1604 }
1605 } // namespace json_details
1606 } // namespace DAW_JSON_VER
1607} // namespace daw::json
Definition: daw_json_value.h:320
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:452
constexpr bool is_null() const
Definition: daw_json_value.h:493
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
auto operator<<(std::ostream &os, T const &value) -> std::enable_if_t< daw::json::json_details::is_opted_into_json_iostreams_v< T >, std::ostream & >
Definition: daw_json_iostream.h:43
ParseState & tmp
Definition: daw_json_iterator.h:37
Iterator & it
Definition: daw_json_traits.h:251
constexpr ymdhms time_point_to_civil(std::chrono::time_point< Clock, Duration > const &tp)
Definition: daw_json_parse_iso8601_utils.h:283
auto use_stream(std::string_view sv)
Definition: to_daw_json_string.h:185
auto to_string_test(T &&v) -> decltype(to_string(DAW_FWD2(T, v)))
decltype(to_string_test(std::declval< T >())) to_string_result
Definition: to_daw_json_string.h:69
constexpr bool has_to_string_v
Definition: to_daw_json_string.h:77
daw::is_detected< to_string_test::to_string_result, T > has_to_string
Definition: to_daw_json_string.h:74
constexpr auto to_string(std::optional< T > const &v) -> decltype(to_string(*v))
Definition: to_daw_json_string.h:55
constexpr void to_variant_string(OutputIterator &it, parse_to_t const &value)
Definition: to_daw_json_string.h:594
constexpr DAW_ATTRIB_INLINE void dependent_member_to_json_str(bool &, OutputIterator const &, TpArgs const &, Value const &, VisitedMembers const &)
Definition: to_daw_json_string.h:1395
std::bool_constant< JsonType::expected_type==JsonParseTypes::Null > is_json_nullable
Definition: daw_json_parse_common.h:284
serialization_policy< OutputIterator, SerializationOptions > to_daw_json_string_tuple(serialization_policy< OutputIterator, SerializationOptions > it, parse_to_t const &value, std::index_sequence< Is... >)
Definition: to_daw_json_string.h:1082
constexpr auto digits100
Definition: to_daw_json_string.h:741
constexpr bool has_istream_op_v
Definition: to_daw_json_string.h:102
decltype(from_string(std::declval< daw::tag_t< T > >(), std::declval< std::string_view >())) from_string_test
Definition: to_daw_json_string.h:83
typename deref_t_impl::deref_type_impl< T >::type dereferenced_t
Definition: daw_json_traits.h:745
constexpr OutputIterator member_to_string(template_param< JsonMember >, OutputIterator it, T const &value)
Definition: to_daw_json_string.h:1340
daw::is_detected< is_a_json_tagged_variant_test, T > is_a_json_tagged_variant
Definition: daw_json_traits.h:472
decltype(operator>>(std::declval< T & >(), std::declval< U const & >())) has_rshift_test
Definition: to_daw_json_string.h:95
decltype(operator<<(std::declval< T & >(), std::declval< U const & >())) has_lshift_test
Definition: to_daw_json_string.h:91
constexpr bool has_from_string_v
Definition: to_daw_json_string.h:86
std::bool_constant< daw::is_detected_v< json_type_t, T > > is_a_json_type
Definition: daw_json_traits.h:446
typename daw::detected_or_t< T, ordered_member_subtype_test, T > ordered_member_subtype_t
Definition: daw_json_parse_common.h:51
constexpr void to_json_ordered_str(std::size_t &array_idx, std::size_t array_size, serialization_policy< OutputIterator, SerializerOptions > &it, Tuple< Args... > const &tp)
Definition: to_daw_json_string.h:1493
constexpr auto has_value(T const &v) -> std::enable_if_t< is_readable_v< T >, bool >
Definition: daw_json_traits.h:62
constexpr char to_nibble_char(Char c)
Definition: to_daw_json_string.h:322
std::underlying_type< T > base_int_type_impl
Definition: to_daw_json_string.h:734
typename JsonMember::dependent_member dependent_member_t
Definition: daw_json_parse_common.h:995
std::uint32_t json_options_t
Definition: daw_json_option_bits.h:23
constexpr Key const & json_get_key(std::pair< Key, Value > const &kv)
Definition: to_daw_json_string.h:1212
constexpr Value const & json_get_value(std::pair< Key, Value > const &kv)
Definition: to_daw_json_string.h:1218
constexpr void utf32_to_utf8(std::uint32_t cp, OutputIterator &it)
Definition: to_daw_json_string.h:353
typename std::conditional_t< std::is_enum_v< T >, base_int_type_impl< T >, daw::traits::identity< T > >::type base_int_type_t
Definition: to_daw_json_string.h:739
constexpr OutputIterator to_daw_json_string(ParseTag< JsonParseTypes::Null >, OutputIterator it, parse_to_t const &value)
constexpr OutputIterator output_hex(std::uint16_t c, OutputIterator it)
Definition: to_daw_json_string.h:334
missing_required_mapping_for< Name > missing_required_mapping_error()
Definition: to_daw_json_string.h:1352
constexpr void to_json_str(bool &is_first, serialization_policy< OutputIterator, SerializationOptions > &it, Tuple const &tp, Value const &, Visited &visited_members)
Definition: to_daw_json_string.h:1455
constexpr bool is_null(std::optional< T > const &v)
Definition: to_daw_json_string.h:951
constexpr bool has_ostream_op_v
Definition: to_daw_json_string.h:98
constexpr OutputIterator to_chars(Real const &value, OutputIterator out_it)
Definition: to_daw_json_string.h:1530
constexpr bool is_string_view_like_v
Definition: daw_json_traits.h:531
static constexpr std::size_t find_names_in_pack_v
Definition: to_daw_json_string.h:1386
constexpr OutputIterator integer_to_string(OutputIterator it, Integer const &value)
Definition: to_daw_json_string.h:893
constexpr OutputIterator copy_to_iterator(OutputIterator it, Container const &container)
Definition: to_daw_json_string.h:391
EightBitModes
Definition: daw_json_type_options.h:143
@ Tuple
A variant type where the Switcher is based on a submember of the class being parsed.
constexpr std::string_view to_string(JsonBaseParseTypes pt)
Definition: daw_json_enums.h:63
daw::constant< v > ParseTag
Definition: daw_json_enums.h:119
constexpr decltype(auto) get(basic_json_pair< ParseState > const &parse_state)
Definition: daw_json_value.h:49
LiteralAsStringOpt
Definition: daw_json_type_options.h:38
typename json_data_contract< T >::type json_data_contract_trait_t
Definition: daw_json_traits.h:135
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
Definition: daw_json_assert.h:39
FPOutputFormat
Definition: daw_json_type_options.h:83
Definition: daw_from_json.h:22
Definition: daw_from_json.h:22
Definition: daw_json_parse_iso8601_utils.h:272
std::int_least32_t year
Definition: daw_json_parse_iso8601_utils.h:273
std::uint_least32_t second
Definition: daw_json_parse_iso8601_utils.h:278
std::uint_least32_t month
Definition: daw_json_parse_iso8601_utils.h:274
std::uint_least32_t hour
Definition: daw_json_parse_iso8601_utils.h:276
std::uint_least32_t day
Definition: daw_json_parse_iso8601_utils.h:275
std::uint_least32_t minute
Definition: daw_json_parse_iso8601_utils.h:277
std::uint_least32_t millisecond
Definition: daw_json_parse_iso8601_utils.h:279
Definition: to_daw_json_string.h:195
Definition: to_daw_json_string.h:115
static auto use_stream(U const &v)
Definition: to_daw_json_string.h:117
Definition: daw_json_traits.h:667
Definition: daw_json_traits.h:127
static constexpr std::size_t find_position()
Definition: to_daw_json_string.h:1366
Definition: daw_json_value_state.h:57
Definition: daw_json_serialize_policy.h:47
Allow tuple like types to be used in json_tuple.
Definition: daw_json_traits.h:672
Definition: to_daw_json_string.h:884
static constexpr LiteralAsStringOpt literal_as_string
Definition: to_daw_json_string.h:886
Integer parse_to_t
Definition: to_daw_json_string.h:885
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16