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