100.00% Lines (285/285) 100.00% Functions (29/29)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/json 7   // Official repository: https://github.com/boostorg/json
8   // 8   //
9   9  
10   #ifndef BOOST_JSON_IMPL_SERIALIZER_IPP 10   #ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
11   #define BOOST_JSON_IMPL_SERIALIZER_IPP 11   #define BOOST_JSON_IMPL_SERIALIZER_IPP
12   12  
  13 + #include <boost/charconv/to_chars.hpp>
13   #include <boost/core/detail/static_assert.hpp> 14   #include <boost/core/detail/static_assert.hpp>
14   #include <boost/json/serializer.hpp> 15   #include <boost/json/serializer.hpp>
15   #include <boost/json/detail/format.hpp> 16   #include <boost/json/detail/format.hpp>
16   #include <boost/json/detail/sse2.hpp> 17   #include <boost/json/detail/sse2.hpp>
17   18  
18   #ifdef _MSC_VER 19   #ifdef _MSC_VER
19   #pragma warning(push) 20   #pragma warning(push)
20   #pragma warning(disable: 4127) // conditional expression is constant 21   #pragma warning(disable: 4127) // conditional expression is constant
21   #endif 22   #endif
22   23  
  24 + namespace {
  25 +
  26 + std::size_t
  27 + BOOST_NOINLINE
HITGNC   28 + 15 format_special(char* dest, double d, bool allow_infinity_and_nan) noexcept
  29 + {
HITGNC   30 + 15 if( std::isinf(d) )
  31 + {
HITGNC   32 + 10 if( std::signbit(d) )
  33 + {
HITGNC   34 + 5 if( allow_infinity_and_nan )
  35 + {
HITGNC   36 + 2 std::memcpy(dest, "-Infinity", 9);
HITGNC   37 + 2 return 9;
  38 + }
  39 + else
  40 + {
HITGNC   41 + 3 std::memcpy(dest, "-1e99999", 8);
HITGNC   42 + 3 return 8;
  43 + }
  44 + }
  45 + else
  46 + {
HITGNC   47 + 5 if( allow_infinity_and_nan )
  48 + {
HITGNC   49 + 2 std::memcpy(dest, "Infinity", 8);
HITGNC   50 + 2 return 8;
  51 + }
  52 + else
  53 + {
HITGNC   54 + 3 std::memcpy(dest, "1e99999", 7);
HITGNC   55 + 3 return 7;
  56 + }
  57 + }
  58 + }
  59 + else
  60 + {
HITGNC   61 + 5 BOOST_ASSERT( std::isnan(d) );
HITGNC   62 + 5 if( allow_infinity_and_nan )
  63 + {
HITGNC   64 + 2 std::memcpy(dest, "NaN", 3);
HITGNC   65 + 2 return 3;
  66 + }
  67 + else
  68 + {
HITGNC   69 + 3 std::memcpy(dest, "null", 4);
HITGNC   70 + 3 return 4;
  71 + }
  72 + }
  73 + }
  74 +
  75 + } // namespace
  76 +
23   namespace boost { 77   namespace boost {
24   namespace json { 78   namespace json {
25   namespace detail { 79   namespace detail {
26   80  
27   struct int64_formatter 81   struct int64_formatter
28   { 82   {
29   std::int64_t i; 83   std::int64_t i;
30   84  
31   std::size_t 85   std::size_t
HITCBC 32   3188 operator()(char* dst) const noexcept 86   3188 operator()(char* dst) const noexcept
33   { 87   {
HITCBC 34   3188 return format_int64(dst, i); 88   3188 return format_int64(dst, i);
35   } 89   }
36   }; 90   };
37   91  
38   struct uint64_formatter 92   struct uint64_formatter
39   { 93   {
40   std::uint64_t u; 94   std::uint64_t u;
41   95  
42   std::size_t 96   std::size_t
HITCBC 43   425 operator()(char* dst) const noexcept 97   425 operator()(char* dst) const noexcept
44   { 98   {
HITCBC 45   425 return format_uint64(dst, u); 99   425 return format_uint64(dst, u);
46   } 100   }
47   }; 101   };
48   102  
49   struct double_formatter 103   struct double_formatter
50   { 104   {
51   double d; 105   double d;
52   bool allow_infinity_and_nan; 106   bool allow_infinity_and_nan;
53   107  
54   std::size_t 108   std::size_t
HITCBC 55   477 operator()(char* dst) const noexcept 109   534 operator()(char* dst) const noexcept
56   { 110   {
HITCBC 57 - 477 return format_double(dst, d, allow_infinity_and_nan); 111 + 534 if(BOOST_JSON_UNLIKELY( !std::isfinite(d)) )
  112 + {
HITGNC   113 + 15 return format_special(dst, d, allow_infinity_and_nan);
  114 + }
  115 +
HITGNC   116 + 519 auto const result = boost::charconv::to_chars(
  117 + dst,
  118 + dst + detail::max_number_chars,
HITGNC   119 + 519 d,
  120 + boost::charconv::chars_format::scientific);
HITGNC   121 + 519 BOOST_ASSERT( result.ec == std::errc() );
HITGNC   122 + 519 return result.ptr - dst;
58   } 123   }
59   }; 124   };
60   125  
HITCBC 61   21245 writer:: 126   21302 writer::
62   writer( 127   writer(
63   storage_ptr sp, 128   storage_ptr sp,
64   unsigned char* buf, 129   unsigned char* buf,
65   std::size_t buf_size, 130   std::size_t buf_size,
HITCBC 66   21245 serialize_options const& opts) noexcept 131   21302 serialize_options const& opts) noexcept
HITCBC 67   21245 : st_( 132   21302 : st_(
HITCBC 68   21245 std::move(sp), 133   21302 std::move(sp),
69   buf, 134   buf,
70   buf_size) 135   buf_size)
HITCBC 71   21245 , opts_(opts) 136   21302 , opts_(opts)
72   { 137   {
73   // ensure room for \uXXXX escape plus one 138   // ensure room for \uXXXX escape plus one
74   BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 ); 139   BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
HITCBC 75   21245 } 140   21302 }
76   141  
77   bool 142   bool
78   BOOST_FORCEINLINE 143   BOOST_FORCEINLINE
79   write_buffer(writer& w, stream& ss0) 144   write_buffer(writer& w, stream& ss0)
80   { 145   {
HITCBC 81   1444 local_stream ss(ss0); 146   1558 local_stream ss(ss0);
HITCBC 82   2578 auto const n = ss.remain(); 147   2744 auto const n = ss.remain();
HITCBC 83   2578 if( n < w.cs0_.remain() ) 148   2744 if( n < w.cs0_.remain() )
84   { 149   {
HITCBC 85   1334 ss.append(w.cs0_.data(), n); 150   1448 ss.append(w.cs0_.data(), n);
HITCBC 86   1334 w.cs0_.skip(n); 151   1448 w.cs0_.skip(n);
HITCBC 87   1334 return w.suspend(writer::state::lit); 152   1448 return w.suspend(writer::state::lit);
88   } 153   }
HITCBC 89   1244 ss.append( w.cs0_.data(), w.cs0_.remain() ); 154   1296 ss.append( w.cs0_.data(), w.cs0_.remain() );
HITCBC 90   1244 return true; 155   1296 return true;
HITCBC 91   2578 } 156   2744 }
92   157  
93   template< class F > 158   template< class F >
94   bool 159   bool
HITCBC 95   4090 write_buffer(writer& w, stream& ss0, F f) 160   4147 write_buffer(writer& w, stream& ss0, F f)
96   { 161   {
HITCBC 97   4090 BOOST_ASSERT( w.st_.empty() ); 162   4147 BOOST_ASSERT( w.st_.empty() );
98   163  
HITCBC 99   4090 local_stream ss(ss0); 164   4147 local_stream ss(ss0);
HITCBC 100   4090 if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars )) 165   4147 if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101   { 166   {
HITCBC 102   2956 ss.advance( f(ss.data()) ); 167   2961 ss.advance( f(ss.data()) );
HITCBC 103   2956 return true; 168   2961 return true;
104   } 169   }
105   170  
HITCBC 106   1134 w.cs0_ = { w.buf_, f(w.buf_) }; 171   1186 w.cs0_ = { w.buf_, f(w.buf_) };
HITCBC 107   1134 return write_buffer(w, ss); 172   1186 return write_buffer(w, ss);
HITCBC 108   4090 } 173   4147 }
109   174  
110   template<literals Lit> 175   template<literals Lit>
111   bool 176   bool
HITCBC 112   4725 write_literal(writer& w, stream& ss) 177   4725 write_literal(writer& w, stream& ss)
113   { 178   {
HITCBC 114   4725 constexpr std::size_t index = literal_index(Lit); 179   4725 constexpr std::size_t index = literal_index(Lit);
HITCBC 115   4725 constexpr char const* literal = literal_strings[index]; 180   4725 constexpr char const* literal = literal_strings[index];
HITCBC 116   4725 constexpr std::size_t sz = literal_sizes[index]; 181   4725 constexpr std::size_t sz = literal_sizes[index];
117   182  
HITCBC 118   4725 std::size_t const n = ss.remain(); 183   4725 std::size_t const n = ss.remain();
HITCBC 119   4725 if(BOOST_JSON_LIKELY( n >= sz )) 184   4725 if(BOOST_JSON_LIKELY( n >= sz ))
120   { 185   {
HITCBC 121   4613 ss.append( literal, sz ); 186   4613 ss.append( literal, sz );
HITCBC 122   4613 return true; 187   4613 return true;
123   } 188   }
124   189  
HITCBC 125   112 ss.append(literal, n); 190   112 ss.append(literal, n);
126   191  
HITCBC 127   112 w.cs0_ = {literal + n, sz - n}; 192   112 w.cs0_ = {literal + n, sz - n};
HITCBC 128   112 return w.suspend(writer::state::lit); 193   112 return w.suspend(writer::state::lit);
129   } 194   }
130   195  
131   bool 196   bool
HITCBC 132   197 write_true(writer& w, stream& ss) 197   197 write_true(writer& w, stream& ss)
133   { 198   {
HITCBC 134   197 return write_literal<literals::true_>(w, ss); 199   197 return write_literal<literals::true_>(w, ss);
135   } 200   }
136   201  
137   bool 202   bool
HITCBC 138   176 write_false(writer& w, stream& ss) 203   176 write_false(writer& w, stream& ss)
139   { 204   {
HITCBC 140   176 return write_literal<literals::false_>(w, ss); 205   176 return write_literal<literals::false_>(w, ss);
141   } 206   }
142   207  
143   bool 208   bool
HITCBC 144   4352 write_null(writer& w, stream& ss) 209   4352 write_null(writer& w, stream& ss)
145   { 210   {
HITCBC 146   4352 return write_literal<literals::null>(w, ss); 211   4352 return write_literal<literals::null>(w, ss);
147   } 212   }
148   213  
149   bool 214   bool
HITCBC 150   3188 write_int64(writer& w, stream& ss0, std::int64_t i) 215   3188 write_int64(writer& w, stream& ss0, std::int64_t i)
151   { 216   {
HITCBC 152   3188 return write_buffer( w, ss0, int64_formatter{i} ); 217   3188 return write_buffer( w, ss0, int64_formatter{i} );
153   } 218   }
154   219  
155   bool 220   bool
HITCBC 156   425 write_uint64(writer& w, stream& ss0, std::uint64_t u) 221   425 write_uint64(writer& w, stream& ss0, std::uint64_t u)
157   { 222   {
HITCBC 158   425 return write_buffer( w, ss0, uint64_formatter{u} ); 223   425 return write_buffer( w, ss0, uint64_formatter{u} );
159   } 224   }
160   225  
161   bool 226   bool
HITCBC 162   477 write_double(writer& w, stream& ss0, double d) 227   534 write_double(writer& w, stream& ss0, double d)
163   { 228   {
HITCBC 164   954 return write_buffer( 229   1068 return write_buffer(
HITCBC 165   477 w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} ); 230   534 w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
166   } 231   }
167   232  
168   bool 233   bool
HITCBC 169   1444 resume_buffer(writer& w, stream& ss0) 234   1558 resume_buffer(writer& w, stream& ss0)
170   { 235   {
HITCBC 171   1444 BOOST_ASSERT( !w.st_.empty() ); 236   1558 BOOST_ASSERT( !w.st_.empty() );
172   writer::state st; 237   writer::state st;
HITCBC 173   1444 w.st_.pop(st); 238   1558 w.st_.pop(st);
HITCBC 174   1444 BOOST_ASSERT(st == writer::state::lit); 239   1558 BOOST_ASSERT(st == writer::state::lit);
175   240  
HITCBC 176   2888 return write_buffer(w, ss0); 241   3116 return write_buffer(w, ss0);
177   } 242   }
178   243  
179   template<bool StackEmpty> 244   template<bool StackEmpty>
180   bool 245   bool
HITCBC 181   44285 do_write_string(writer& w, stream& ss0) 246   44285 do_write_string(writer& w, stream& ss0)
182   { 247   {
HITCBC 183   44285 local_stream ss(ss0); 248   44285 local_stream ss(ss0);
HITCBC 184   44285 local_const_stream cs(w.cs0_); 249   44285 local_const_stream cs(w.cs0_);
HITCBC 185   9812 if(! StackEmpty && ! w.st_.empty()) 250   9812 if(! StackEmpty && ! w.st_.empty())
186   { 251   {
187   writer::state st; 252   writer::state st;
HITCBC 188   9812 w.st_.pop(st); 253   9812 w.st_.pop(st);
HITCBC 189   9812 switch(st) 254   9812 switch(st)
190   { 255   {
HITCBC 191   170 default: 256   170 default:
HITCBC 192   170 case writer::state::str1: goto do_str1; 257   170 case writer::state::str1: goto do_str1;
HITCBC 193   268 case writer::state::str2: goto do_str2; 258   268 case writer::state::str2: goto do_str2;
HITCBC 194   9082 case writer::state::str3: goto do_str3; 259   9082 case writer::state::str3: goto do_str3;
HITCBC 195   52 case writer::state::esc1: goto do_esc1; 260   52 case writer::state::esc1: goto do_esc1;
HITCBC 196   48 case writer::state::utf1: goto do_utf1; 261   48 case writer::state::utf1: goto do_utf1;
HITCBC 197   48 case writer::state::utf2: goto do_utf2; 262   48 case writer::state::utf2: goto do_utf2;
HITCBC 198   48 case writer::state::utf3: goto do_utf3; 263   48 case writer::state::utf3: goto do_utf3;
HITCBC 199   48 case writer::state::utf4: goto do_utf4; 264   48 case writer::state::utf4: goto do_utf4;
HITCBC 200   48 case writer::state::utf5: goto do_utf5; 265   48 case writer::state::utf5: goto do_utf5;
201   } 266   }
202   } 267   }
203   static constexpr char hex[] = "0123456789abcdef"; 268   static constexpr char hex[] = "0123456789abcdef";
204   static constexpr char esc[] = 269   static constexpr char esc[] =
205   "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu" 270   "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
206   "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 271   "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
207   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0" 272   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
208   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 273   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
209   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 274   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
210   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 275   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
211   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 276   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
212   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 277   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
213   278  
214   // opening quote 279   // opening quote
HITCBC 215   34473 do_str1: 280   34473 do_str1:
HITCBC 216   34643 if(BOOST_JSON_LIKELY(ss)) 281   34643 if(BOOST_JSON_LIKELY(ss))
HITCBC 217   34473 ss.append('\x22'); // '"' 282   34473 ss.append('\x22'); // '"'
218   else 283   else
HITCBC 219   170 return w.suspend(writer::state::str1); 284   170 return w.suspend(writer::state::str1);
220   285  
221   // fast loop, 286   // fast loop,
222   // copy unescaped 287   // copy unescaped
HITCBC 223   34741 do_str2: 288   34741 do_str2:
HITCBC 224   34741 if(BOOST_JSON_LIKELY(ss)) 289   34741 if(BOOST_JSON_LIKELY(ss))
225   { 290   {
HITCBC 226   34485 std::size_t n = cs.remain(); 291   34485 std::size_t n = cs.remain();
HITCBC 227   34485 if(BOOST_JSON_LIKELY(n > 0)) 292   34485 if(BOOST_JSON_LIKELY(n > 0))
228   { 293   {
HITCBC 229   34441 if(ss.remain() > n) 294   34441 if(ss.remain() > n)
HITCBC 230   25766 n = detail::count_unescaped( 295   25766 n = detail::count_unescaped(
231   cs.data(), n); 296   cs.data(), n);
232   else 297   else
HITCBC 233   8675 n = detail::count_unescaped( 298   8675 n = detail::count_unescaped(
234   cs.data(), ss.remain()); 299   cs.data(), ss.remain());
HITCBC 235   34441 if(n > 0) 300   34441 if(n > 0)
236   { 301   {
HITCBC 237   25225 ss.append(cs.data(), n); 302   25225 ss.append(cs.data(), n);
HITCBC 238   25225 cs.skip(n); 303   25225 cs.skip(n);
HITCBC 239   25225 if(! ss) 304   25225 if(! ss)
HITCBC 240   12 return w.suspend(writer::state::str2); 305   12 return w.suspend(writer::state::str2);
241   } 306   }
242   } 307   }
243   else 308   else
244   { 309   {
HITCBC 245   44 ss.append('\x22'); // '"' 310   44 ss.append('\x22'); // '"'
HITCBC 246   44 return true; 311   44 return true;
247   } 312   }
248   } 313   }
249   else 314   else
250   { 315   {
HITCBC 251   256 return w.suspend(writer::state::str2); 316   256 return w.suspend(writer::state::str2);
252   } 317   }
253   318  
254   // slow loop, 319   // slow loop,
255   // handle escapes 320   // handle escapes
HITCBC 256   43707 do_str3: 321   43707 do_str3:
HITCBC 257   31461016 while(BOOST_JSON_LIKELY(ss)) 322   31461016 while(BOOST_JSON_LIKELY(ss))
258   { 323   {
HITCBC 259   31451934 if(BOOST_JSON_LIKELY(cs)) 324   31451934 if(BOOST_JSON_LIKELY(cs))
260   { 325   {
HITCBC 261   31417505 auto const ch = *cs; 326   31417505 auto const ch = *cs;
HITCBC 262   31417505 auto const c = esc[static_cast< 327   31417505 auto const c = esc[static_cast<
263   unsigned char>(ch)]; 328   unsigned char>(ch)];
HITCBC 264   31417505 ++cs; 329   31417505 ++cs;
HITCBC 265   31417505 if(! c) 330   31417505 if(! c)
266   { 331   {
HITCBC 267   31416777 ss.append(ch); 332   31416777 ss.append(ch);
268   } 333   }
HITCBC 269   728 else if(c != 'u') 334   728 else if(c != 'u')
270   { 335   {
HITCBC 271   376 ss.append('\\'); 336   376 ss.append('\\');
HITCBC 272   376 if(BOOST_JSON_LIKELY(ss)) 337   376 if(BOOST_JSON_LIKELY(ss))
273   { 338   {
HITCBC 274   324 ss.append(c); 339   324 ss.append(c);
275   } 340   }
276   else 341   else
277   { 342   {
HITCBC 278   52 w.buf_[0] = c; 343   52 w.buf_[0] = c;
HITCBC 279   52 return w.suspend( 344   52 return w.suspend(
HITCBC 280   52 writer::state::esc1); 345   52 writer::state::esc1);
281   } 346   }
282   } 347   }
283   else 348   else
284   { 349   {
HITCBC 285   352 if(BOOST_JSON_LIKELY( 350   352 if(BOOST_JSON_LIKELY(
286   ss.remain() >= 6)) 351   ss.remain() >= 6))
287   { 352   {
HITCBC 288   208 ss.append("\\u00", 4); 353   208 ss.append("\\u00", 4);
HITCBC 289   208 ss.append(hex[static_cast< 354   208 ss.append(hex[static_cast<
HITCBC 290   208 unsigned char>(ch) >> 4]); 355   208 unsigned char>(ch) >> 4]);
HITCBC 291   208 ss.append(hex[static_cast< 356   208 ss.append(hex[static_cast<
HITCBC 292   208 unsigned char>(ch) & 15]); 357   208 unsigned char>(ch) & 15]);
293   } 358   }
294   else 359   else
295   { 360   {
HITCBC 296   144 ss.append('\\'); 361   144 ss.append('\\');
HITCBC 297   144 w.buf_[0] = hex[static_cast< 362   144 w.buf_[0] = hex[static_cast<
HITCBC 298   144 unsigned char>(ch) >> 4]; 363   144 unsigned char>(ch) >> 4];
HITCBC 299   144 w.buf_[1] = hex[static_cast< 364   144 w.buf_[1] = hex[static_cast<
HITCBC 300   144 unsigned char>(ch) & 15]; 365   144 unsigned char>(ch) & 15];
HITCBC 301   144 goto do_utf1; 366   144 goto do_utf1;
302   } 367   }
303   } 368   }
304   } 369   }
305   else 370   else
306   { 371   {
HITCBC 307   34429 ss.append('\x22'); // '"' 372   34429 ss.append('\x22'); // '"'
HITCBC 308   34429 return true; 373   34429 return true;
309   } 374   }
310   } 375   }
HITCBC 311   9082 return w.suspend(writer::state::str3); 376   9082 return w.suspend(writer::state::str3);
312   377  
HITCBC 313   52 do_esc1: 378   52 do_esc1:
HITCBC 314   52 BOOST_ASSERT(ss); 379   52 BOOST_ASSERT(ss);
HITCBC 315   52 ss.append(w.buf_[0]); 380   52 ss.append(w.buf_[0]);
HITCBC 316   52 goto do_str3; 381   52 goto do_str3;
317   382  
HITCBC 318   192 do_utf1: 383   192 do_utf1:
HITCBC 319   192 if(BOOST_JSON_LIKELY(ss)) 384   192 if(BOOST_JSON_LIKELY(ss))
HITCBC 320   144 ss.append('u'); 385   144 ss.append('u');
321   else 386   else
HITCBC 322   48 return w.suspend(writer::state::utf1); 387   48 return w.suspend(writer::state::utf1);
HITCBC 323   192 do_utf2: 388   192 do_utf2:
HITCBC 324   192 if(BOOST_JSON_LIKELY(ss)) 389   192 if(BOOST_JSON_LIKELY(ss))
HITCBC 325   144 ss.append('0'); 390   144 ss.append('0');
326   else 391   else
HITCBC 327   48 return w.suspend(writer::state::utf2); 392   48 return w.suspend(writer::state::utf2);
HITCBC 328   192 do_utf3: 393   192 do_utf3:
HITCBC 329   192 if(BOOST_JSON_LIKELY(ss)) 394   192 if(BOOST_JSON_LIKELY(ss))
HITCBC 330   144 ss.append('0'); 395   144 ss.append('0');
331   else 396   else
HITCBC 332   48 return w.suspend(writer::state::utf3); 397   48 return w.suspend(writer::state::utf3);
HITCBC 333   192 do_utf4: 398   192 do_utf4:
HITCBC 334   192 if(BOOST_JSON_LIKELY(ss)) 399   192 if(BOOST_JSON_LIKELY(ss))
HITCBC 335   144 ss.append(w.buf_[0]); 400   144 ss.append(w.buf_[0]);
336   else 401   else
HITCBC 337   48 return w.suspend(writer::state::utf4); 402   48 return w.suspend(writer::state::utf4);
HITCBC 338   192 do_utf5: 403   192 do_utf5:
HITCBC 339   192 if(BOOST_JSON_LIKELY(ss)) 404   192 if(BOOST_JSON_LIKELY(ss))
HITCBC 340   144 ss.append(w.buf_[1]); 405   144 ss.append(w.buf_[1]);
341   else 406   else
HITCBC 342   48 return w.suspend(writer::state::utf5); 407   48 return w.suspend(writer::state::utf5);
HITCBC 343   144 goto do_str3; 408   144 goto do_str3;
HITCBC 344   44285 } 409   44285 }
345   410  
346   bool 411   bool
HITCBC 347   19827 write_string(writer& w, stream& ss0) 412   19827 write_string(writer& w, stream& ss0)
348   { 413   {
HITCBC 349   19827 return do_write_string<true>(w, ss0); 414   19827 return do_write_string<true>(w, ss0);
350   } 415   }
351   416  
352   bool 417   bool
HITCBC 353   408 resume_string(writer& w, stream& ss0) 418   408 resume_string(writer& w, stream& ss0)
354   { 419   {
HITCBC 355   408 return do_write_string<false>(w, ss0); 420   408 return do_write_string<false>(w, ss0);
356   } 421   }
357   422  
358   template<bool StackEmpty> 423   template<bool StackEmpty>
359   bool 424   bool
360   write_value(writer& w, stream& ss); 425   write_value(writer& w, stream& ss);
361   426  
362   template< class T, bool StackEmpty > 427   template< class T, bool StackEmpty >
363   BOOST_FORCEINLINE 428   BOOST_FORCEINLINE
364   bool 429   bool
365   write_impl(no_conversion_tag, writer& w, stream& ss) 430   write_impl(no_conversion_tag, writer& w, stream& ss)
366   { 431   {
HITCBC 367   34536 return write_value<StackEmpty>(w, ss); 432   34575 return write_value<StackEmpty>(w, ss);
368   } 433   }
369   434  
370   template<bool StackEmpty> 435   template<bool StackEmpty>
371   bool 436   bool
HITCBC 372   6041 write_array(writer& w, stream& ss) 437   6080 write_array(writer& w, stream& ss)
373   { 438   {
HITCBC 374   6040 return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss); 439   6079 return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375   } 440   }
376   441  
377   template<bool StackEmpty> 442   template<bool StackEmpty>
378   bool 443   bool
HITCBC 379   27194 write_object(writer& w, stream& ss) 444   27194 write_object(writer& w, stream& ss)
380   { 445   {
HITCBC 381   27194 return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss); 446   27194 return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382   } 447   }
383   448  
384   template<bool StackEmpty> 449   template<bool StackEmpty>
385   bool 450   bool
HITCBC 386   66927 write_value(writer& w, stream& ss) 451   67131 write_value(writer& w, stream& ss)
387   { 452   {
HITCBC 388   22905 if(StackEmpty || w.st_.empty()) 453   23041 if(StackEmpty || w.st_.empty())
389   { 454   {
HITCBC 390   44503 BOOST_ASSERT( w.p_ ); 455   44571 BOOST_ASSERT( w.p_ );
HITCBC 391   44503 auto const pv = reinterpret_cast<value const*>(w.p_); 456   44571 auto const pv = reinterpret_cast<value const*>(w.p_);
HITCBC 392   44503 switch(pv->kind()) 457   44571 switch(pv->kind())
393   { 458   {
HITCBC 394   18083 default: 459   18083 default:
395   case kind::object: 460   case kind::object:
HITCBC 396   18083 w.p_ = &pv->get_object(); 461   18083 w.p_ = &pv->get_object();
HITCBC 397   18083 return write_object<true>(w, ss); 462   18083 return write_object<true>(w, ss);
398   463  
HITCBC 399   3400 case kind::array: 464   3413 case kind::array:
HITCBC 400   3400 w.p_ = &pv->get_array(); 465   3413 w.p_ = &pv->get_array();
HITCBC 401   3400 return write_array<true>(w, ss); 466   3413 return write_array<true>(w, ss);
402   467  
HITCBC 403   14643 case kind::string: 468   14643 case kind::string:
404   { 469   {
HITCBC 405   14643 auto const& js = pv->get_string(); 470   14643 auto const& js = pv->get_string();
HITCBC 406   14643 w.cs0_ = { js.data(), js.size() }; 471   14643 w.cs0_ = { js.data(), js.size() };
HITCBC 407   14643 return do_write_string<true>(w, ss); 472   14643 return do_write_string<true>(w, ss);
408   } 473   }
409   474  
HITCBC 410   3182 case kind::int64: 475   3182 case kind::int64:
HITCBC 411   3182 return write_int64( w, ss, pv->get_int64() ); 476   3182 return write_int64( w, ss, pv->get_int64() );
HITCBC 412   91 case kind::uint64: 477   91 case kind::uint64:
HITCBC 413   91 return write_uint64( w, ss, pv->get_uint64() ); 478   91 return write_uint64( w, ss, pv->get_uint64() );
HITCBC 414   467 case kind::double_: 479   522 case kind::double_:
HITCBC 415   467 return write_double( w, ss, pv->get_double() ); 480   522 return write_double( w, ss, pv->get_double() );
416   481  
HITCBC 417   306 case kind::bool_: 482   306 case kind::bool_:
HITCBC 418   306 if( pv->get_bool() ) 483   306 if( pv->get_bool() )
HITCBC 419   139 return write_true(w, ss); 484   139 return write_true(w, ss);
420   else 485   else
HITCBC 421   167 return write_false(w, ss); 486   167 return write_false(w, ss);
422   487  
HITCBC 423   4331 case kind::null: 488   4331 case kind::null:
HITCBC 424   4331 return write_null(w, ss); 489   4331 return write_null(w, ss);
425   } 490   }
426   } 491   }
427   else 492   else
428   { 493   {
429   writer::state st; 494   writer::state st;
HITCBC 430   22424 w.st_.peek(st); 495   22560 w.st_.peek(st);
HITCBC 431   22424 switch(st) 496   22560 switch(st)
432   { 497   {
HITCBC 433   1324 default: 498   1434 default:
434   case writer::state::lit: 499   case writer::state::lit:
HITCBC 435   1324 return resume_buffer(w, ss); 500   1434 return resume_buffer(w, ss);
436   501  
HITCBC 437   9404 case writer::state::str1: case writer::state::str2: 502   9404 case writer::state::str1: case writer::state::str2:
438   case writer::state::str3: case writer::state::esc1: 503   case writer::state::str3: case writer::state::esc1:
439   case writer::state::utf1: case writer::state::utf2: 504   case writer::state::utf1: case writer::state::utf2:
440   case writer::state::utf3: case writer::state::utf4: 505   case writer::state::utf3: case writer::state::utf4:
441   case writer::state::utf5: 506   case writer::state::utf5:
HITCBC 442   9404 return do_write_string<false>(w, ss); 507   9404 return do_write_string<false>(w, ss);
443   508  
HITCBC 444   2636 case writer::state::arr1: case writer::state::arr2: 509   2662 case writer::state::arr1: case writer::state::arr2:
445   case writer::state::arr3: case writer::state::arr4: 510   case writer::state::arr3: case writer::state::arr4:
HITCBC 446   2636 return write_array<StackEmpty>(w, ss); 511   2662 return write_array<StackEmpty>(w, ss);
447   512  
HITCBC 448   9060 case writer::state::obj1: case writer::state::obj2: 513   9060 case writer::state::obj1: case writer::state::obj2:
449   case writer::state::obj3: case writer::state::obj4: 514   case writer::state::obj3: case writer::state::obj4:
450   case writer::state::obj5: case writer::state::obj6: 515   case writer::state::obj5: case writer::state::obj6:
HITCBC 451   9060 return write_object<StackEmpty>(w, ss); 516   9060 return write_object<StackEmpty>(w, ss);
452   } 517   }
453   } 518   }
454   } 519   }
455   520  
456   } // namespace detail 521   } // namespace detail
457   522  
HITCBC 458   2348 serializer:: 523   2405 serializer::
HITCBC 459   2348 serializer(serialize_options const& opts) noexcept 524   2405 serializer(serialize_options const& opts) noexcept
HITCBC 460   2348 : serializer({}, nullptr, 0, opts) 525   2405 : serializer({}, nullptr, 0, opts)
HITCBC 461   2348 {} 526   2405 {}
462   527  
HITCBC 463   21245 serializer:: 528   21302 serializer::
464   serializer( 529   serializer(
465   storage_ptr sp, 530   storage_ptr sp,
466   unsigned char* buf, 531   unsigned char* buf,
467   std::size_t buf_size, 532   std::size_t buf_size,
HITCBC 468   21245 serialize_options const& opts) noexcept 533   21302 serialize_options const& opts) noexcept
HITCBC 469   21245 : detail::writer(std::move(sp), buf, buf_size, opts) 534   21302 : detail::writer(std::move(sp), buf, buf_size, opts)
HITCBC 470   21245 {} 535   21302 {}
471   536  
472   void 537   void
HITCBC 473   20961 serializer:: 538   21016 serializer::
474   reset(value const* p) noexcept 539   reset(value const* p) noexcept
475   { 540   {
HITCBC 476   20961 p_ = p; 541   21016 p_ = p;
HITCBC 477   20961 fn0_ = &detail::write_value<true>; 542   21016 fn0_ = &detail::write_value<true>;
HITCBC 478   20961 fn1_ = &detail::write_value<false>; 543   21016 fn1_ = &detail::write_value<false>;
HITCBC 479   20961 st_.clear(); 544   21016 st_.clear();
HITCBC 480   20961 done_ = false; 545   21016 done_ = false;
HITCBC 481   20961 } 546   21016 }
482   547  
483   void 548   void
HITCBC 484   5 serializer:: 549   5 serializer::
485   reset(array const* p) noexcept 550   reset(array const* p) noexcept
486   { 551   {
HITCBC 487   5 p_ = p; 552   5 p_ = p;
HITCBC 488   5 fn0_ = &detail::write_array<true>; 553   5 fn0_ = &detail::write_array<true>;
HITCBC 489   5 fn1_ = &detail::write_array<false>; 554   5 fn1_ = &detail::write_array<false>;
HITCBC 490   5 st_.clear(); 555   5 st_.clear();
HITCBC 491   5 done_ = false; 556   5 done_ = false;
HITCBC 492   5 } 557   5 }
493   558  
494   void 559   void
HITCBC 495   51 serializer:: 560   51 serializer::
496   reset(object const* p) noexcept 561   reset(object const* p) noexcept
497   { 562   {
HITCBC 498   51 p_ = p; 563   51 p_ = p;
HITCBC 499   51 fn0_ = &detail::write_object<true>; 564   51 fn0_ = &detail::write_object<true>;
HITCBC 500   51 fn1_ = &detail::write_object<false>; 565   51 fn1_ = &detail::write_object<false>;
HITCBC 501   51 st_.clear(); 566   51 st_.clear();
HITCBC 502   51 done_ = false; 567   51 done_ = false;
HITCBC 503   51 } 568   51 }
504   569  
505   void 570   void
HITCBC 506   2 serializer:: 571   2 serializer::
507   reset(string const* p) noexcept 572   reset(string const* p) noexcept
508   { 573   {
HITCBC 509   2 cs0_ = { p->data(), p->size() }; 574   2 cs0_ = { p->data(), p->size() };
HITCBC 510   2 fn0_ = &detail::do_write_string<true>; 575   2 fn0_ = &detail::do_write_string<true>;
HITCBC 511   2 fn1_ = &detail::do_write_string<false>; 576   2 fn1_ = &detail::do_write_string<false>;
HITCBC 512   2 st_.clear(); 577   2 st_.clear();
HITCBC 513   2 done_ = false; 578   2 done_ = false;
HITCBC 514   2 } 579   2 }
515   580  
516   void 581   void
HITCBC 517   1 serializer:: 582   1 serializer::
518   reset(string_view sv) noexcept 583   reset(string_view sv) noexcept
519   { 584   {
HITCBC 520   1 cs0_ = { sv.data(), sv.size() }; 585   1 cs0_ = { sv.data(), sv.size() };
HITCBC 521   1 fn0_ = &detail::do_write_string<true>; 586   1 fn0_ = &detail::do_write_string<true>;
HITCBC 522   1 fn1_ = &detail::do_write_string<false>; 587   1 fn1_ = &detail::do_write_string<false>;
HITCBC 523   1 st_.clear(); 588   1 st_.clear();
HITCBC 524   1 done_ = false; 589   1 done_ = false;
HITCBC 525   1 } 590   1 }
526   591  
527   void 592   void
HITCBC 528   6 serializer::reset(std::nullptr_t) noexcept 593   6 serializer::reset(std::nullptr_t) noexcept
529   { 594   {
HITCBC 530   6 p_ = nullptr; 595   6 p_ = nullptr;
HITCBC 531   6 fn0_ = &detail::write_impl<std::nullptr_t, true>; 596   6 fn0_ = &detail::write_impl<std::nullptr_t, true>;
HITCBC 532   6 fn1_ = &detail::write_impl<std::nullptr_t, false>; 597   6 fn1_ = &detail::write_impl<std::nullptr_t, false>;
HITCBC 533   6 st_.clear(); 598   6 st_.clear();
HITCBC 534   6 done_ = false; 599   6 done_ = false;
HITCBC 535   6 } 600   6 }
536   601  
537   string_view 602   string_view
HITCBC 538   32983 serializer:: 603   33154 serializer::
539   read(char* dest, std::size_t size) 604   read(char* dest, std::size_t size)
540   { 605   {
HITCBC 541   32983 if( !fn0_ ) 606   33154 if( !fn0_ )
HITCBC 542   6 reset(nullptr); 607   6 reset(nullptr);
543   608  
HITCBC 544   32983 if(BOOST_JSON_UNLIKELY(size == 0)) 609   33154 if(BOOST_JSON_UNLIKELY(size == 0))
HITCBC 545   1 return {dest, 0}; 610   1 return {dest, 0};
546   611  
HITCBC 547   32982 detail::stream ss(dest, size); 612   33153 detail::stream ss(dest, size);
HITCBC 548   32982 if(st_.empty()) 613   33153 if(st_.empty())
HITCBC 549   21244 fn0_(*this, ss); 614   21301 fn0_(*this, ss);
550   else 615   else
HITCBC 551   11738 fn1_(*this, ss); 616   11852 fn1_(*this, ss);
HITCBC 552   32980 if(st_.empty()) 617   33151 if(st_.empty())
553   { 618   {
HITCBC 554   21242 done_ = true; 619   21299 done_ = true;
HITCBC 555   21242 fn0_ = nullptr; 620   21299 fn0_ = nullptr;
HITCBC 556   21242 p_ = nullptr; 621   21299 p_ = nullptr;
557   } 622   }
HITCBC 558   32980 return string_view( 623   33151 return string_view(
HITCBC 559   32980 dest, ss.used(dest)); 624   33151 dest, ss.used(dest));
560   } 625   }
561   626  
562   } // namespace json 627   } // namespace json
563   } // namespace boost 628   } // namespace boost
564   629  
565   #ifdef _MSC_VER 630   #ifdef _MSC_VER
566   #pragma warning(pop) 631   #pragma warning(pop)
567   #endif 632   #endif
568   633  
569   #endif 634   #endif