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