DAW JSON Link
daw_json_to_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 "daw_json_assert.h"
13 #include "daw_json_value.h"
14 #include "namespace.h"
15 
16 #include <daw/daw_algorithm.h>
17 #include <daw/daw_arith_traits.h>
18 #include <daw/daw_bounded_vector.h>
19 #include <daw/daw_move.h>
20 #include <daw/daw_traits.h>
21 #include <utf8/unchecked.h>
22 
23 #include <array>
24 #include <ciso646>
25 #include <optional>
26 #include <sstream>
27 #include <string>
28 #ifndef DAW_JSON_CUSTOM_D2S
29 #include <third_party/dragonbox/dragonbox.h>
30 #elif __has_include( "custom_d2s.h" )
31 #include "custom_d2s.h"
32 #else
33 #error Request for local d2s, but no custom_d2s.h supplied with char * d2s( Real const & value, char * ); declaration/definition in namespace daw::json
34 #endif
35 #include <tuple>
36 #include <type_traits>
37 #include <variant>
38 
39 namespace DAW_JSON_NS {
40  template<typename Real, typename OutputIterator>
41  inline OutputIterator real2string( Real const &value,
42  OutputIterator out_it ) {
43  // TODO: Customization point, add to readme
44 #ifndef DAW_JSON_CUSTOM_D2S
45  if constexpr( std::is_same_v<Real, float> ) {
46  return jkj::dragonbox::to_chars_n( value, out_it );
47  } else {
48  return jkj::dragonbox::to_chars_n( static_cast<double>( value ), out_it );
49  }
50 #else
51  if constexpr( std::is_same_v<Real, float> ) {
52  return DAW_JSON_NS::d2s( value, out_it );
53  } else {
54  return DAW_JSON_NS::d2s( static_cast<double>( value ), out_it );
55  }
56 #endif
57  }
58 } // namespace DAW_JSON_NS
59 
61  // Need to use ADL to_string in unevaluated contexts. Limiting to it's own
62  // namespace
63  using std::to_string;
64  namespace to_string_test {
65  template<typename T>
66  [[maybe_unused]] auto to_string_test( T &&v )
67  -> decltype( to_string( DAW_FWD( v ) ) );
68 
69  template<typename T>
70  using to_string_result = decltype( to_string_test( std::declval<T>( ) ) );
71  } // namespace to_string_test
72 
73  template<typename T>
74  using has_to_string = daw::is_detected<to_string_test::to_string_result, T>;
75 
76  template<typename T>
77  inline constexpr bool has_to_string_v = has_to_string<T>::value;
78 
79  template<typename T>
80  [[nodiscard, maybe_unused]] auto to_string( std::optional<T> const &v )
81  -> decltype( to_string( *v ) ) {
82  if( not v ) {
83  return { "null" };
84  }
85  return to_string( *v );
86  }
87 } // namespace DAW_JSON_NS::json_details::to_strings
88 
89 namespace DAW_JSON_NS {
90  template<typename T>
92  template<typename U,
93  std::enable_if_t<json_details::to_strings::has_to_string_v<U>,
94  std::nullptr_t> = nullptr>
95  [[nodiscard]] inline constexpr decltype( auto )
96  operator( )( U &&value ) const {
97  using std::to_string;
98  return to_string( DAW_FWD( value ) );
99  }
100 
101  template<typename U,
102  std::enable_if_t<not json_details::to_strings::has_to_string_v<U>,
103  std::nullptr_t> = nullptr>
104  [[nodiscard]] inline std::string operator( )( U &&value ) const {
105  std::stringstream ss;
106  ss << DAW_FWD( value );
107  return ss.str( );
108  }
109  };
110 } // namespace DAW_JSON_NS
111 
112 namespace DAW_JSON_NS::json_details {
113  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
114  [[nodiscard]] inline OutputIterator constexpr to_string(
115  ParseTag<JsonParseTypes::Null>, OutputIterator it,
116  parse_to_t const &value );
117 
118  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
119  [[nodiscard]] constexpr OutputIterator
120  to_string( ParseTag<JsonParseTypes::Array>, OutputIterator it,
121  parse_to_t const &value );
122 
123  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
124  [[nodiscard]] constexpr OutputIterator
126  parse_to_t const &value );
127 
128  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
129  [[nodiscard]] constexpr OutputIterator
130  to_string( ParseTag<JsonParseTypes::KeyValue>, OutputIterator it,
131  parse_to_t const &value );
132 
133  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
134  [[nodiscard]] constexpr OutputIterator
135  to_string( ParseTag<JsonParseTypes::Custom>, OutputIterator it,
136  parse_to_t const &value );
137 
138  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
139  [[nodiscard]] constexpr OutputIterator
140  to_string( ParseTag<JsonParseTypes::Variant>, OutputIterator it,
141  parse_to_t const &value );
142 
143  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
144  [[nodiscard]] constexpr OutputIterator
145  to_string( ParseTag<JsonParseTypes::Class>, OutputIterator it,
146  parse_to_t const &value );
147 
148  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
149  [[nodiscard]] OutputIterator to_string( ParseTag<JsonParseTypes::Real>,
150  OutputIterator it,
151  parse_to_t const &value );
152 
153  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
154  [[nodiscard]] constexpr OutputIterator
155  to_string( ParseTag<JsonParseTypes::Signed>, OutputIterator it,
156  parse_to_t const &value );
157 
158  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
159  [[nodiscard]] constexpr OutputIterator
160  to_string( ParseTag<JsonParseTypes::Unsigned>, OutputIterator it,
161  parse_to_t const &value );
162 
163  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
164  [[nodiscard]] constexpr OutputIterator
166  parse_to_t const &value );
167 
168  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
169  [[nodiscard]] constexpr OutputIterator
171  parse_to_t const &value );
172 
173  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
174  [[nodiscard]] constexpr OutputIterator
175  to_string( ParseTag<JsonParseTypes::Date>, OutputIterator it,
176  parse_to_t const &value );
177 
178  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
179  [[nodiscard]] constexpr OutputIterator
180  to_string( ParseTag<JsonParseTypes::Bool>, OutputIterator it,
181  parse_to_t const &value );
182 
183  //************************************************
184  template<typename Char>
185  constexpr char to_nibble_char( Char c ) {
186  auto const u = static_cast<unsigned>( static_cast<unsigned char>( c ) );
187  daw_json_assert( u < 16, ErrorReason::InvalidUTFEscape );
188  if( u < 10 ) {
189  return static_cast<char>( u + static_cast<unsigned char>( '0' ) );
190  } else {
191  return static_cast<char>( ( u - 10U ) +
192  static_cast<unsigned char>( 'A' ) );
193  }
194  }
195 
196  template<typename OutputIterator>
197  constexpr OutputIterator output_hex( std::uint16_t c, OutputIterator it ) {
198  char const nibbles[] = { '\\',
199  'u',
200  to_nibble_char( ( c >> 12U ) & 0xFU ),
201  to_nibble_char( ( c >> 8U ) & 0xFU ),
202  to_nibble_char( ( c >> 4U ) & 0xFU ),
203  to_nibble_char( c & 0xFU ) };
204 
205  *it++ = nibbles[0];
206  *it++ = nibbles[1];
207  *it++ = nibbles[2];
208  *it++ = nibbles[3];
209  *it++ = nibbles[4];
210  *it++ = nibbles[5];
211  return it;
212  }
213 
214  template<typename OutputIterator>
215  constexpr void utf32_to_utf8( std::uint32_t cp, OutputIterator &it ) {
216  if( cp <= 0x7FU ) {
217  *it++ = static_cast<char>( cp );
218  return;
219  }
220  if( cp <= 0x7FFU ) {
221  *it++ = static_cast<char>( ( cp >> 6U ) | 0b11000000U );
222  *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
223  return;
224  }
225  if( cp <= 0xFFFFU ) {
226  *it++ = static_cast<char>( ( cp >> 12U ) | 0b11100000U );
227  *it++ = static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U );
228  *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
229  return;
230  }
231  if( cp <= 0x10FFFFU ) {
232  *it++ = static_cast<char>( ( cp >> 18U ) | 0b11110000U );
233  *it++ =
234  static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U );
235  *it++ = static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U );
236  *it++ = static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U );
237  return;
238  }
239  daw_json_error( ErrorReason::InvalidUTFCodepoint );
240  }
241 } // namespace DAW_JSON_NS::json_details
242 
244  template<bool do_escape = false,
246  typename OutputIterator, typename Container,
247  daw::enable_when_t<traits::is_container_like_v<
248  daw::remove_cvref_t<Container>>> = nullptr>
249  [[nodiscard]] constexpr OutputIterator
250  copy_to_iterator( OutputIterator it, Container const &container ) {
251  if constexpr( do_escape ) {
252  using iter = daw::remove_cvref_t<decltype( std::begin( container ) )>;
253  using it_t = utf8::unchecked::iterator<iter>;
254  auto first = it_t( std::begin( container ) );
255  auto const last = it_t( std::end( container ) );
256  while( first != last ) {
257  auto const cp = *first++;
258  switch( cp ) {
259  case '"':
260  *it++ = '\\';
261  *it++ = '"';
262  break;
263  case '\\':
264  *it++ = '\\';
265  *it++ = '\\';
266  break;
267  case '\b':
268  *it++ = '\\';
269  *it++ = 'b';
270  break;
271  case '\f':
272  *it++ = '\\';
273  *it++ = 'f';
274  break;
275  case '\n':
276  *it++ = '\\';
277  *it++ = 'n';
278  break;
279  case '\r':
280  *it++ = '\\';
281  *it++ = 'r';
282  break;
283  case '\t':
284  *it++ = '\\';
285  *it++ = 't';
286  break;
287  default:
288  if( cp < 0x20U ) {
289  it =
290  json_details::output_hex( static_cast<std::uint16_t>( cp ), it );
291  break;
292  }
293  if constexpr( EightBitMode == EightBitModes::DisallowHigh ) {
294  if( cp >= 0x7FU and cp <= 0xFFFFU ) {
295  it = json_details::output_hex( static_cast<std::uint16_t>( cp ),
296  it );
297  break;
298  }
299  if( cp > 0xFFFFU ) {
301  static_cast<std::uint16_t>( 0xD7C0U + ( cp >> 10U ) ), it );
303  static_cast<std::uint16_t>( 0xDC00U + ( cp & 0x3FFU ) ), it );
304  break;
305  }
306  }
307  json_details::utf32_to_utf8( cp, it );
308  break;
309  }
310  }
311  } else {
312  for( auto c : container ) {
313  if constexpr( EightBitMode == EightBitModes::DisallowHigh ) {
314  daw_json_assert( ( static_cast<unsigned char>( c ) >= 0x20U and
315  static_cast<unsigned char>( c ) <= 0x7FU ),
316  ErrorReason::InvalidStringHighASCII );
317  }
318  *it++ = c;
319  }
320  }
321  return it;
322  }
323 
324  template<bool do_escape = false,
326  typename OutputIterator>
327  [[nodiscard]] constexpr OutputIterator copy_to_iterator( OutputIterator it,
328  char const *ptr ) {
329  if( ptr == nullptr ) {
330  return it;
331  }
332  if constexpr( do_escape ) {
333 
334  auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
335  while( *chr_it.base( ) != '\0' ) {
336  auto const cp = *chr_it++;
337  switch( cp ) {
338  case '"':
339  *it++ = '\\';
340  *it++ = '"';
341  break;
342  case '\\':
343  *it++ = '\\';
344  *it++ = '\\';
345  break;
346  case '\b':
347  *it++ = '\\';
348  *it++ = 'b';
349  break;
350  case '\f':
351  *it++ = '\\';
352  *it++ = 'f';
353  break;
354  case '\n':
355  *it++ = '\\';
356  *it++ = 'n';
357  break;
358  case '\r':
359  *it++ = '\\';
360  *it++ = 'r';
361  break;
362  case '\t':
363  *it++ = '\\';
364  *it++ = 't';
365  break;
366  default:
367  if( cp < 0x20U ) {
368  it =
369  json_details::output_hex( static_cast<std::uint16_t>( cp ), it );
370  break;
371  }
372  if constexpr( EightBitMode == EightBitModes::DisallowHigh ) {
373  if( cp >= 0x7FU and cp <= 0xFFFFU ) {
374  it = json_details::output_hex( static_cast<std::uint16_t>( cp ),
375  it );
376  break;
377  }
378  if( cp > 0xFFFFU ) {
380  static_cast<std::uint16_t>( 0xD7C0U + ( cp >> 10U ) ), it );
381  it = output_hex(
382  static_cast<std::uint16_t>( 0xDC00U + ( cp & 0x3FFU ) ), it );
383  break;
384  }
385  }
386  json_details::utf32_to_utf8( cp, it );
387  break;
388  }
389  }
390  } else {
391  while( *ptr != '\0' ) {
392  if constexpr( EightBitMode == EightBitModes::DisallowHigh ) {
393  daw_json_assert( ( static_cast<unsigned>( *ptr ) >= 0x20U and
394  static_cast<unsigned>( *ptr ) <= 0x7FU ),
395  ErrorReason::InvalidStringHighASCII );
396  }
397  *it++ = *ptr++;
398  }
399  }
400  return it;
401  }
402 
403  template<bool do_escape = false,
405  typename OutputIterator, typename Range>
406  [[nodiscard]] constexpr OutputIterator
407  copy_to_iterator( OutputIterator it, basic_json_value<Range> const &jv ) {
408  if( jv.is_null( ) ) {
409  return copy_to_iterator<do_escape, EightBitMode>( it, "null" );
410  } else {
411  return copy_to_iterator<do_escape, EightBitMode>( it,
412  jv.get_string_view( ) );
413  }
414  }
415 } // namespace DAW_JSON_NS::utils
416 
417 namespace DAW_JSON_NS::json_details {
418  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
419  [[nodiscard]] constexpr OutputIterator
421  parse_to_t const &value ) {
422 
423  if constexpr( JsonMember::literal_as_string ==
425  *it++ = '"';
426  }
427  if( value ) {
428  it = utils::copy_to_iterator( it, "true" );
429  } else {
430  it = utils::copy_to_iterator( it, "false" );
431  }
432  if constexpr( JsonMember::literal_as_string ==
434  *it++ = '"';
435  }
436  return it;
437  }
438 
439  template<std::size_t idx, typename JsonMembers, typename OutputIterator,
440  typename parse_to_t>
441  constexpr void to_variant_string( OutputIterator &it,
442  parse_to_t const &value ) {
443  if constexpr( idx < std::variant_size_v<parse_to_t> ) {
444  if( value.index( ) != idx ) {
445  to_variant_string<idx + 1, JsonMembers>( it, value );
446  return;
447  }
448  using element_t = typename JsonMembers::json_elements;
449  using JsonMember =
450  typename std::tuple_element<idx,
451  typename element_t::element_map_t>::type;
452  it = to_string<JsonMember>( ParseTag<JsonMember::base_expected_type>{ },
453  it, std::get<idx>( value ) );
454  }
455  }
456 
457  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
458  [[nodiscard]] inline constexpr OutputIterator
460  parse_to_t const &value ) {
461 
462  to_variant_string<0, JsonMember>( it, value );
463  return it;
464  }
465 
466  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
467  [[nodiscard]] inline constexpr OutputIterator
469  parse_to_t const &value ) {
470 
471  to_variant_string<0, JsonMember>( it, value );
472  return it;
473  }
474 
475  template<typename T>
476  [[maybe_unused]] constexpr auto deref_detect( T &&value )
477  -> decltype( *value );
478 
479  [[maybe_unused]] inline constexpr void deref_detect( ... ) {}
480 
481  template<typename T>
482  using deref_t =
483  daw::remove_cvref_t<decltype( deref_detect( std::declval<T>( ) ) )>;
484 
485  template<typename Optional>
486  inline constexpr bool is_valid_optional_v =
487  daw::is_detected_v<deref_t, Optional>;
488 
489  template<typename JsonMember, typename OutputIterator, typename Optional>
490  [[nodiscard]] inline constexpr OutputIterator
492  Optional const &value ) {
493  static_assert( is_valid_optional_v<Optional> );
494  daw_json_assert( value, ErrorReason::UnexpectedNull );
496  return to_string<JsonMember>( tag_type{ }, it, *value );
497  }
498 
499  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
500  [[nodiscard]] inline OutputIterator to_string( ParseTag<JsonParseTypes::Real>,
501  OutputIterator it,
502  parse_to_t const &value ) {
503 
504  static_assert(
505  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
506  "value must be convertible to specified type in class contract" );
507 
508  if constexpr( std::is_floating_point_v<typename JsonMember::parse_to_t> ) {
509  if( std::isnan( value ) ) {
510  if constexpr( JsonMember::literal_as_string ==
512  daw_json_error( ErrorReason::NumberIsNaN );
513  } else {
514  *it++ = '"';
515  it = utils::copy_to_iterator( it, "NaN" );
516  *it++ = '"';
517  return it;
518  }
519  } else if( std::isinf( value ) ) {
520  if constexpr( JsonMember::literal_as_string ==
522  daw_json_error( ErrorReason::NumberIsInf );
523  } else {
524  *it++ = '"';
525  it = utils::copy_to_iterator( it, "Infinity" );
526  *it++ = '"';
527  return it;
528  }
529  }
530  }
531 
532  if constexpr( JsonMember::literal_as_string ==
534  *it++ = '"';
535  }
536  if constexpr( daw::is_floating_point_v<parse_to_t> ) {
537  static_assert( sizeof( parse_to_t ) <= sizeof( double ) );
538  if constexpr( std::is_same_v<OutputIterator, char *> ) {
539  it = real2string( value, it );
540  } else {
541  char buff[50];
542  buff[49] = 0;
543  char *ptr = buff;
544  ptr = real2string( value, ptr );
545  std::copy( buff, ptr, it );
546  }
547  } else {
548  using std::to_string;
549  using to_strings::to_string;
550  it = utils::copy_to_iterator( it, to_string( value ) );
551  }
552  if constexpr( JsonMember::literal_as_string ==
554  *it++ = '"';
555  }
556  return it;
557  }
558 
559  template<typename T, bool>
561  using type = T;
562  };
563 
564  template<typename T>
565  struct base_int_type_impl<T, true> {
566  using type = std::underlying_type_t<T>;
567  };
568 
569  template<typename T>
572 
573  inline constexpr auto digits100 = [] {
574  std::array<char[2], 100> result{ };
575  for( size_t n = 0; n < 100; ++n ) {
576  result[n][0] =
577  static_cast<char>( ( n % 10 ) + static_cast<unsigned char>( '0' ) );
578  result[n][1] =
579  static_cast<char>( ( n / 10 ) + static_cast<unsigned char>( '0' ) );
580  }
581  return result;
582  }( );
583 
584  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
585  [[nodiscard]] constexpr OutputIterator
587  parse_to_t const &value ) {
588 
589  static_assert(
590  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
591  "value must be convertible to specified type in class contract" );
592 
593  using std::to_string;
594  using to_strings::to_string;
595  using under_type = base_int_type_t<parse_to_t>;
596 
597  if constexpr( JsonMember::literal_as_string ==
599  *it++ = '"';
600  }
601  if constexpr( std::is_enum_v<parse_to_t> or
602  daw::is_integral_v<parse_to_t> ) {
603  auto v = static_cast<under_type>( value );
604 
605  char buff[daw::numeric_limits<under_type>::digits10 + 1]{ };
606  char *ptr = buff;
607  if( v < 0 ) {
608  *it++ = '-';
609  // Do 1 round here just incase we are
610  // daw::numeric_limits<intmax_t>::min( ) and cannot negate
611  *ptr++ = '0' - static_cast<char>( v % 10 );
612  v /= -10;
613  if( v == 0 ) {
614  *it++ = buff[0];
615  if constexpr( JsonMember::literal_as_string ==
617  *it++ = '"';
618  }
619  return it;
620  }
621  }
622  if( v == 0 ) {
623  *ptr++ = '0';
624  }
625  while( v >= 10 ) {
626  auto const tmp = static_cast<std::size_t>( v % 100 );
627  v /= 100;
628  ptr[0] = digits100[tmp][0];
629  ptr[1] = digits100[tmp][1];
630  ptr += 2;
631  }
632  if( v > 0 ) {
633  *ptr++ = '0' + static_cast<char>( v );
634  }
635  --ptr;
636  *it++ = *ptr;
637  while( ptr != buff ) {
638  --ptr;
639  *it++ = *ptr;
640  }
641  } else {
642  // Fallback to ADL
643  it = utils::copy_to_iterator( it, to_string( value ) );
644  }
645  if constexpr( JsonMember::literal_as_string ==
647  *it++ = '"';
648  }
649  return it;
650  }
651 
652  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
653  [[nodiscard]] constexpr OutputIterator
655  parse_to_t const &value ) {
656 
657  static_assert(
658  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
659  "value must be convertible to specified type in class contract" );
660 
661  using std::to_string;
662  using to_strings::to_string;
663  using under_type = base_int_type_t<parse_to_t>;
664 
665  if constexpr( JsonMember::literal_as_string ==
667  *it++ = '"';
668  }
669  if constexpr( std::is_enum_v<parse_to_t> or
670  daw::is_integral_v<parse_to_t> ) {
671  auto v = static_cast<under_type>( value );
672  daw_json_assert( v >= 0, ErrorReason::NumberOutOfRange );
673  char buff[daw::numeric_limits<under_type>::digits10 + 1]{ };
674  char *ptr = buff;
675  if( v == 0 ) {
676  *ptr++ = '0';
677  }
678  while( v >= 10 ) {
679  auto const tmp = static_cast<std::size_t>( v % 100 );
680  v /= 100;
681  ptr[0] = digits100[tmp][0];
682  ptr[1] = digits100[tmp][1];
683  ptr += 2;
684  }
685  if( v > 0 ) {
686  *ptr++ = '0' + static_cast<char>( v );
687  }
688  --ptr;
689  *it++ = *ptr;
690  while( ptr != buff ) {
691  --ptr;
692  *it++ = *ptr;
693  }
694  } else {
695  // Fallback to ADL
696  it = utils::copy_to_iterator( it, to_string( value ) );
697  }
698  if constexpr( JsonMember::literal_as_string ==
700  *it++ = '"';
701  }
702  return it;
703  }
704 
705 } // namespace DAW_JSON_NS::json_details
706 
707 namespace DAW_JSON_NS::utils {
708  namespace utils_details {
709  namespace {
710  template<typename Integer>
711  struct number {
712  using parse_to_t = Integer;
715  };
716  } // namespace
717  } // namespace utils_details
718 
719  template<typename Integer, typename OutputIterator>
720  inline constexpr OutputIterator integer_to_string( OutputIterator it,
721  Integer const &value ) {
722  static_assert( daw::is_integral_v<Integer> );
723 
724  if constexpr( daw::is_unsigned_v<Integer> ) {
725  return json_details::to_string<utils_details::number<Integer>>(
726  ParseTag<JsonParseTypes::Unsigned>{ }, it, value );
727  } else {
728  return json_details::to_string<utils_details::number<Integer>>(
729  ParseTag<JsonParseTypes::Signed>{ }, it, value );
730  }
731  }
732 } // namespace DAW_JSON_NS::utils
733 
734 namespace DAW_JSON_NS::json_details {
735  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
736  [[nodiscard]] inline constexpr OutputIterator
738  parse_to_t const &value ) {
739 
740  static_assert(
741  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
742  "value must be convertible to specified type in class contract" );
743 
744  constexpr EightBitModes eight_bit_mode = JsonMember::eight_bit_mode;
745  *it++ = '"';
746  if( std::size( value ) > 0U ) {
747  it = utils::copy_to_iterator<false, eight_bit_mode>( it, value );
748  }
749  *it++ = '"';
750  return it;
751  }
752 
753  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
754  [[nodiscard]] inline constexpr OutputIterator
756  parse_to_t const &value ) {
757 
758  /* TODO is something like this necessary
759  static_assert(
760  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
761  "value must be convertible to specified type in class contract" );
762  */
763 
764  constexpr EightBitModes eight_bit_mode = JsonMember::eight_bit_mode;
765  *it++ = '"';
766  it = utils::copy_to_iterator<true, eight_bit_mode>( it, value );
767  *it++ = '"';
768  return it;
769  }
770 
771  template<typename T>
772  [[nodiscard]] inline constexpr bool is_null( std::optional<T> const &v ) {
773  return not static_cast<bool>( v );
774  }
775 
776  template<typename T>
777  [[nodiscard]] inline constexpr bool is_null( T const & ) {
778  return false;
779  }
780 
781  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
782  [[nodiscard]] constexpr OutputIterator
784  parse_to_t const &value ) {
785 
786  static_assert(
787  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
788  "value must be convertible to specified type in class contract" );
789 
791  if( is_null( value ) ) {
792  it = utils::copy_to_iterator( it, "null" );
793  } else {
794  *it++ = '"';
795  datetime::ymdhms const civil = datetime::time_point_to_civil( value );
796  it = utils::integer_to_string( it, civil.year );
797  *it++ = '-';
798  if( civil.month < 10 ) {
799  *it++ = '0';
800  }
801  it = utils::integer_to_string( it, civil.month );
802  *it++ = '-';
803  if( civil.day < 10 ) {
804  *it++ = '0';
805  }
806  it = utils::integer_to_string( it, civil.day );
807  *it++ = 'T';
808  if( civil.hour < 10 ) {
809  *it++ = '0';
810  }
811  it = utils::integer_to_string( it, civil.hour );
812  *it++ = ':';
813  if( civil.minute < 10 ) {
814  *it++ = '0';
815  }
816  it = utils::integer_to_string( it, civil.minute );
817  *it++ = ':';
818  if( civil.second < 10 ) {
819  *it++ = '0';
820  }
821  it = utils::integer_to_string( it, civil.second );
822  if( civil.millisecond > 0 ) {
823  *it++ = '.';
824  it = utils::integer_to_string( it, civil.millisecond );
825  }
826  *it++ = 'Z';
827  *it++ = '"';
828  }
829  return it;
830  }
831 
832  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
833  [[nodiscard]] inline constexpr OutputIterator
835  parse_to_t const &value ) {
836 
837  return utils::copy_to_iterator( it, value );
838  }
839 
840  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
841  [[nodiscard]] inline constexpr OutputIterator
843  parse_to_t const &value ) {
844 
845  static_assert(
846  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
847  "value must be convertible to specified type in class contract" );
848 
849  if constexpr( has_json_to_json_data_v<parse_to_t> ) {
852  value );
853  } else {
854  static_assert( is_submember_tagged_variant_v<parse_to_t> );
856  }
857  }
858 
859  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
860  [[nodiscard]] inline constexpr OutputIterator
862  parse_to_t const &value ) {
863 
864  static_assert(
865  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
866  "value must be convertible to specified type in class contract" );
867 
868  if constexpr( JsonMember::custom_json_type != CustomJsonTypes::Literal ) {
869  *it++ = '"';
870  if constexpr( std::is_invocable_r_v<OutputIterator,
871  typename JsonMember::to_converter_t,
872  OutputIterator, parse_to_t> ) {
873 
874  it = typename JsonMember::to_converter_t{ }( it, value );
875  } else {
877  it, typename JsonMember::to_converter_t{ }( value ) );
878  }
879  *it++ = '"';
880  return it;
881  } else {
883  it, typename JsonMember::to_converter_t{ }( value ) );
884  }
885  }
886 
887  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
888  [[nodiscard]] constexpr OutputIterator
890  parse_to_t const &value ) {
891 
892  static_assert(
893  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
894  "value must be convertible to specified type in class contract" );
895 
896  *it++ = '[';
897  if( not std::empty( value ) ) {
898  auto count = std::size( value ) - 1U;
899  for( auto const &v : value ) {
900  it = to_string<typename JsonMember::json_element_t>(
902  if( count-- > 0 ) {
903  *it++ = ',';
904  }
905  }
906  }
907  *it++ = ']';
908  return it;
909  }
910 
911  template<typename Key, typename Value>
912  [[maybe_unused]] inline constexpr Key const &
913  json_get_key( std::pair<Key, Value> const &kv ) {
914  return kv.first;
915  }
916 
917  template<typename Key, typename Value>
918  [[maybe_unused]] inline constexpr Value const &
919  json_get_value( std::pair<Key, Value> const &kv ) {
920  return kv.second;
921  }
922 
923  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
924  [[nodiscard]] constexpr OutputIterator
926  parse_to_t const &value ) {
927 
928  static_assert(
929  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
930  "value must be convertible to specified type in class contract" );
931  using key_t = typename JsonMember::json_key_t;
932  using value_t = typename JsonMember::json_value_t;
933  *it++ = '[';
934  if( not std::empty( value ) ) {
935  auto count = std::size( value ) - 1U;
936  for( auto const &v : value ) {
937  *it++ = '{';
938  // Append Key Name
939  *it++ = '"';
940  it = utils::copy_to_iterator( it, key_t::name );
941  *it++ = '"';
942  *it++ = ':';
943  // Append Key Value
944  it = to_string<key_t>( ParseTag<key_t::expected_type>{ }, it,
945  json_get_key( v ) );
946 
947  *it++ = ',';
948  // Append Value Name
949  *it++ = '"';
950  it = utils::copy_to_iterator( it, value_t::name );
951  *it++ = '"';
952  *it++ = ':';
953  // Append Value Value
954  it = to_string<value_t>( ParseTag<value_t::expected_type>{ }, it,
955  json_get_value( v ) );
956 
957  *it++ = '}';
958  if( count-- > 0 ) {
959  *it++ = ',';
960  }
961  }
962  }
963  *it++ = ']';
964  return it;
965  }
966 
967  template<typename JsonMember, typename OutputIterator, typename parse_to_t>
968  [[nodiscard]] constexpr OutputIterator
970  parse_to_t const &value ) {
971 
972  static_assert(
973  std::is_convertible_v<parse_to_t, typename JsonMember::parse_to_t>,
974  "value must be convertible to specified type in class contract" );
975 
976  *it++ = '{';
977  if( not std::empty( value ) ) {
978  auto count = std::size( value ) - 1U;
979  for( auto const &v : value ) {
980  it = to_string<typename JsonMember::json_key_t>(
982  json_get_key( v ) );
983  *it++ = ':';
984  it = to_string<typename JsonMember::json_element_t>(
986  json_get_value( v ) );
987  if( count-- > 0 ) {
988  *it++ = ',';
989  }
990  }
991  }
992  *it++ = '}';
993  return it;
994  }
995 
996  template<typename JsonMember, typename OutputIterator, typename T>
997  [[nodiscard]] inline constexpr OutputIterator
998  member_to_string( OutputIterator it, T const &value ) {
999  return to_string<JsonMember>( ParseTag<JsonMember::expected_type>{ },
1000  DAW_MOVE( it ), value );
1001  }
1002 
1003  template<typename JsonMember>
1004  using tag_member_t = typename JsonMember::tag_member;
1005 
1006  template<typename JsonMember>
1007  inline constexpr bool has_tag_member_v =
1008  daw::is_detected_v<tag_member_t, JsonMember>;
1009  template<std::size_t, typename JsonMember, typename OutputIterator,
1010  typename Value, typename VisitedMembers,
1011  std::enable_if_t<not has_tag_member_v<JsonMember>, std::nullptr_t> =
1012  nullptr>
1013  inline constexpr void tags_to_json_str( bool &, OutputIterator const &,
1014  Value const &,
1015  VisitedMembers const & ) {}
1016  template<
1017  std::size_t pos, typename JsonMember, typename OutputIterator,
1018  typename Value, typename VisitedMembers,
1019  std::enable_if_t<has_tag_member_v<JsonMember>, std::nullptr_t> = nullptr>
1020  constexpr void tags_to_json_str( bool &is_first, OutputIterator it,
1021  Value const &v,
1022  VisitedMembers &visited_members ) {
1023  using tag_member = tag_member_t<JsonMember>;
1024  constexpr auto tag_member_name = daw::string_view(
1025  std::data( tag_member::name ), std::size( tag_member::name ) );
1026  if( daw::algorithm::contains( std::data( visited_members ),
1027  daw::data_end( visited_members ),
1028  tag_member_name ) ) {
1029  return;
1030  }
1031  visited_members.push_back( tag_member_name );
1032  if( not is_first ) {
1033  *it++ = ',';
1034  }
1035  is_first = false;
1036  *it++ = '"';
1037  it = utils::copy_to_iterator<false, EightBitModes::AllowFull>(
1038  it, tag_member_name );
1039  it = utils::copy_to_iterator<false, EightBitModes::AllowFull>( it, "\":" );
1040  it = member_to_string<tag_member>( DAW_MOVE( it ),
1041  typename JsonMember::switcher{ }( v ) );
1042  }
1043 
1044  template<std::size_t pos, typename JsonMember, typename OutputIterator,
1045  typename... Args, typename Value, typename Visited>
1046  inline constexpr void to_json_str( bool &is_first, OutputIterator &it,
1047  std::tuple<Args...> const &tp,
1048  Value const &, Visited &visited_members ) {
1049  constexpr auto json_member_name = daw::string_view(
1050  std::data( JsonMember::name ), std::size( JsonMember::name ) );
1051  if( daw::algorithm::contains( std::data( visited_members ),
1052  daw::data_end( visited_members ),
1053  json_member_name ) ) {
1054  return;
1055  }
1056  visited_members.push_back( json_member_name );
1057  static_assert( is_a_json_type_v<JsonMember>, "Unsupported data type" );
1058  if constexpr( is_json_nullable_v<JsonMember> ) {
1059  if( not std::get<pos>( tp ) ) {
1060  return;
1061  }
1062  }
1063  if( not is_first ) {
1064  *it++ = ',';
1065  }
1066  is_first = false;
1067  *it++ = '"';
1068  it = utils::copy_to_iterator<false, EightBitModes::AllowFull>(
1069  it, JsonMember::name );
1070  it = utils::copy_to_iterator<false, EightBitModes::AllowFull>( it, "\":" );
1071  it = member_to_string<JsonMember>( DAW_MOVE( it ), std::get<pos>( tp ) );
1072  }
1073 
1074  template<size_t TupleIdx, typename JsonMember, typename OutputIterator,
1075  typename... Args>
1076  constexpr void to_json_ordered_str( std::size_t &array_idx,
1077  OutputIterator &it,
1078  std::tuple<Args...> const &tp ) {
1079 
1080  using json_member_type = ordered_member_subtype_t<JsonMember>;
1081  static_assert( is_a_json_type_v<json_member_type>,
1082  "Unsupported data type" );
1083  // json_tagged_variant like members cannot work as we have no member names
1084  // to work with
1085  static_assert(
1086  not is_a_json_tagged_variant_v<json_member_type>,
1087  "JSON tagged variant types are not supported when inside an array "
1088  "as an ordered structure" );
1089 
1090  if constexpr( is_an_ordered_member_v<JsonMember> ) {
1091  for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1092  if( array_idx > 0 ) {
1093  *it++ = ',';
1094  }
1095  *it++ = 'n';
1096  *it++ = 'u';
1097  *it++ = 'l';
1098  *it++ = 'l';
1099  }
1100  }
1101  if( array_idx > 0 ) {
1102  *it++ = ',';
1103  }
1104  it = member_to_string<json_member_type>( it, std::get<TupleIdx>( tp ) );
1105  ++array_idx;
1106  }
1107 } // namespace DAW_JSON_NS::json_details
Definition: daw_json_value.h:305
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:426
constexpr bool is_null() const
Definition: daw_json_value.h:457
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:191
static constexpr LiteralAsStringOpt literal_as_string
Definition: daw_json_to_string.h:713
constexpr ymdhms time_point_to_civil(std::chrono::time_point< Clock, Duration > const &tp)
Definition: daw_json_parse_iso8601_utils.h:268
decltype(to_string_test(std::declval< T >())) to_string_result
Definition: daw_json_to_string.h:70
auto to_string_test(T &&v) -> decltype(to_string(DAW_FWD(v)))
Definition: daw_json_to_string.h:60
auto to_string(std::optional< T > const &v) -> decltype(to_string(*v))
Definition: daw_json_to_string.h:80
constexpr bool has_to_string_v
Definition: daw_json_to_string.h:77
daw::is_detected< to_string_test::to_string_result, T > has_to_string
Definition: daw_json_to_string.h:74
Definition: daw_from_json_fwd.h:19
constexpr OutputIterator to_string(ParseTag< JsonParseTypes::Null >, OutputIterator it, parse_to_t const &value)
constexpr void utf32_to_utf8(std::uint32_t cp, OutputIterator &it)
Definition: daw_json_to_string.h:215
typename ordered_member_subtype< T, is_an_ordered_member_v< T > >::type ordered_member_subtype_t
Definition: daw_json_parse_common.h:68
constexpr OutputIterator output_hex(std::uint16_t c, OutputIterator it)
Definition: daw_json_to_string.h:197
constexpr auto digits100
Definition: daw_json_to_string.h:573
constexpr bool has_tag_member_v
Definition: daw_json_to_string.h:1007
constexpr Value const & json_get_value(std::pair< Key, Value > const &kv)
Definition: daw_json_to_string.h:919
constexpr void to_variant_string(OutputIterator &it, parse_to_t const &value)
Definition: daw_json_to_string.h:441
constexpr bool is_valid_optional_v
Definition: daw_json_to_string.h:486
constexpr char to_nibble_char(Char c)
Definition: daw_json_to_string.h:185
constexpr OutputIterator member_to_string(OutputIterator it, T const &value)
Definition: daw_json_to_string.h:998
constexpr bool is_null(std::optional< T > const &v)
Definition: daw_json_to_string.h:772
typename base_int_type_impl< T, std::is_enum_v< T > >::type base_int_type_t
Definition: daw_json_to_string.h:571
constexpr void tags_to_json_str(bool &, OutputIterator const &, Value const &, VisitedMembers const &)
Definition: daw_json_to_string.h:1013
constexpr Key const & json_get_key(std::pair< Key, Value > const &kv)
Definition: daw_json_to_string.h:913
constexpr OutputIterator to_string(ParseTag< JsonParseTypes::Unknown >, OutputIterator it, parse_to_t const &value)
Definition: daw_json_to_string.h:834
typename JsonMember::tag_member tag_member_t
Definition: daw_json_to_string.h:1004
daw::remove_cvref_t< decltype(deref_detect(std::declval< T >()))> deref_t
Definition: daw_json_to_string.h:483
constexpr void to_json_str(bool &is_first, OutputIterator &it, std::tuple< Args... > const &tp, Value const &, Visited &visited_members)
Definition: daw_json_to_string.h:1046
constexpr auto deref_detect(T &&value) -> decltype(*value)
constexpr void to_json_ordered_str(std::size_t &array_idx, OutputIterator &it, std::tuple< Args... > const &tp)
Definition: daw_json_to_string.h:1076
Definition: daw_json_to_string.h:243
constexpr OutputIterator copy_to_iterator(OutputIterator it, Container const &container)
Definition: daw_json_to_string.h:250
constexpr OutputIterator integer_to_string(OutputIterator it, Integer const &value)
Definition: daw_json_to_string.h:720
Definition: daw_from_json.h:22
LiteralAsStringOpt
Definition: daw_json_enums.h:97
std::integral_constant< JsonParseTypes, v > ParseTag
Definition: daw_json_enums.h:89
EightBitModes
Definition: daw_json_enums.h:69
constexpr std::string_view to_string(JsonBaseParseTypes pt)
Definition: daw_json_enums.h:47
typename DAW_JSON_NS::json_data_contract< T >::type json_data_contract_trait_t
Definition: daw_json_traits.h:47
DAW_JSON_NOINLINE void daw_json_error(ErrorReason reason)
Definition: daw_json_assert.h:53
OutputIterator real2string(Real const &value, OutputIterator out_it)
Definition: daw_json_to_string.h:41
Definition: daw_json_to_string.h:91
Definition: daw_json_parse_iso8601_utils.h:256
std::uint_least32_t hour
Definition: daw_json_parse_iso8601_utils.h:260
std::int_least32_t year
Definition: daw_json_parse_iso8601_utils.h:257
std::uint_least32_t month
Definition: daw_json_parse_iso8601_utils.h:258
std::uint_least32_t millisecond
Definition: daw_json_parse_iso8601_utils.h:263
std::uint_least32_t day
Definition: daw_json_parse_iso8601_utils.h:259
std::uint_least32_t second
Definition: daw_json_parse_iso8601_utils.h:262
std::uint_least32_t minute
Definition: daw_json_parse_iso8601_utils.h:261
Definition: daw_json_traits.h:41
std::underlying_type_t< T > type
Definition: daw_json_to_string.h:566
Definition: daw_json_to_string.h:560
T type
Definition: daw_json_to_string.h:561
Definition: daw_json_value_state.h:55