97.83% Lines (180/184) 100.00% Functions (5/5)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru) 2   // Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru)
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_HPP 10   #ifndef BOOST_JSON_IMPL_SERIALIZER_HPP
11   #define BOOST_JSON_IMPL_SERIALIZER_HPP 11   #define BOOST_JSON_IMPL_SERIALIZER_HPP
12   12  
13   #include <boost/core/detail/static_assert.hpp> 13   #include <boost/core/detail/static_assert.hpp>
14   #include <boost/describe/enum_to_string.hpp> 14   #include <boost/describe/enum_to_string.hpp>
15   #include <boost/json/conversion.hpp> 15   #include <boost/json/conversion.hpp>
16   #include <cstddef> 16   #include <cstddef>
17   17  
18   namespace boost { 18   namespace boost {
19   namespace json { 19   namespace json {
20   namespace detail { 20   namespace detail {
21   21  
22   enum class writer::state : char 22   enum class writer::state : char
23   { 23   {
24   str1, str2, str3, esc1, utf1, 24   str1, str2, str3, esc1, utf1,
25   utf2, utf3, utf4, utf5, 25   utf2, utf3, utf4, utf5,
26   lit, 26   lit,
27   arr1, arr2, arr3, arr4, 27   arr1, arr2, arr3, arr4,
28   obj1, obj2, obj3, obj4, obj5, obj6 28   obj1, obj2, obj3, obj4, obj5, obj6
29   }; 29   };
30   30  
31   bool 31   bool
HITCBC 32   11258 writer:: 32   11328 writer::
33   suspend(state st) 33   suspend(state st)
34   { 34   {
HITCBC 35   11258 st_.push(st); 35   11328 st_.push(st);
HITCBC 36   11257 return false; 36   11327 return false;
37   } 37   }
38   38  
39   template<class U, class T> 39   template<class U, class T>
40   bool 40   bool
HITCBC 41   11875 writer:: 41   11947 writer::
42   suspend(state st, U u, T const* pt) 42   suspend(state st, U u, T const* pt)
43   { 43   {
HITCBC 44   11875 st_.push(pt); 44   11947 st_.push(pt);
HITCBC 45   11874 st_.push(u); 45   11946 st_.push(u);
HITCBC 46   11874 st_.push(st); 46   11946 st_.push(st);
HITCBC 47   11874 return false; 47   11946 return false;
48   } 48   }
49   49  
50   template<class T, bool StackEmpty> 50   template<class T, bool StackEmpty>
51   bool 51   bool
52   write_impl(writer& w, stream& ss); 52   write_impl(writer& w, stream& ss);
53   53  
54   template<class T, bool StackEmpty> 54   template<class T, bool StackEmpty>
55   BOOST_FORCEINLINE 55   BOOST_FORCEINLINE
56   bool 56   bool
57   write_impl(null_like_conversion_tag, writer& w, stream& ss) 57   write_impl(null_like_conversion_tag, writer& w, stream& ss)
58   { 58   {
59   #if defined(_MSC_VER) 59   #if defined(_MSC_VER)
60   # pragma warning( push ) 60   # pragma warning( push )
61   # pragma warning( disable : 4127 ) 61   # pragma warning( disable : 4127 )
62   #endif 62   #endif
HITCBC 63   14 if( StackEmpty || w.st_.empty() ) 63   14 if( StackEmpty || w.st_.empty() )
HITCBC 64   20 return write_null(w, ss); 64   20 return write_null(w, ss);
65   #if defined(_MSC_VER) 65   #if defined(_MSC_VER)
66   # pragma warning( pop ) 66   # pragma warning( pop )
67   #endif 67   #endif
HITCBC 68   14 return resume_buffer(w, ss); 68   14 return resume_buffer(w, ss);
69   } 69   }
70   70  
71   template<class T, bool StackEmpty> 71   template<class T, bool StackEmpty>
72   BOOST_FORCEINLINE 72   BOOST_FORCEINLINE
73   bool 73   bool
74   write_impl(bool_conversion_tag, writer& w, stream& ss) 74   write_impl(bool_conversion_tag, writer& w, stream& ss)
75   { 75   {
MISUBC 76   BOOST_ASSERT( w.p_ ); 76   BOOST_ASSERT( w.p_ );
HITCBC 77   97 auto const t = *reinterpret_cast<T const*>(w.p_); 77   97 auto const t = *reinterpret_cast<T const*>(w.p_);
78   78  
79   #if defined(_MSC_VER) 79   #if defined(_MSC_VER)
80   # pragma warning( push ) 80   # pragma warning( push )
81   # pragma warning( disable : 4127 ) 81   # pragma warning( disable : 4127 )
82   #endif 82   #endif
HITCBC 83   61 if( StackEmpty || w.st_.empty() ) 83   61 if( StackEmpty || w.st_.empty() )
84   #if defined(_MSC_VER) 84   #if defined(_MSC_VER)
85   # pragma warning( pop ) 85   # pragma warning( pop )
86   #endif 86   #endif
87   { 87   {
HITCBC 88   67 if( t ) 88   67 if( t )
HITCBC 89   58 return write_true(w, ss); 89   58 return write_true(w, ss);
90   else 90   else
HITCBC 91   9 return write_false(w, ss); 91   9 return write_false(w, ss);
92   } 92   }
93   93  
HITCBC 94   30 return resume_buffer(w, ss); 94   30 return resume_buffer(w, ss);
95   } 95   }
96   96  
97   template<class T, bool StackEmpty> 97   template<class T, bool StackEmpty>
98   BOOST_FORCEINLINE 98   BOOST_FORCEINLINE
99   bool 99   bool
100   write_impl(integral_conversion_tag, writer& w, stream& ss0) 100   write_impl(integral_conversion_tag, writer& w, stream& ss0)
101   { 101   {
102   #if defined(_MSC_VER) 102   #if defined(_MSC_VER)
103   # pragma warning( push ) 103   # pragma warning( push )
104   # pragma warning( disable : 4127 ) 104   # pragma warning( disable : 4127 )
105   #endif 105   #endif
HITCBC 106   200 if( StackEmpty || w.st_.empty() ) 106   200 if( StackEmpty || w.st_.empty() )
107   #if defined(_MSC_VER) 107   #if defined(_MSC_VER)
108   # pragma warning( pop ) 108   # pragma warning( pop )
109   #endif 109   #endif
110   { 110   {
HITCBC 111   6 auto const& t = *reinterpret_cast<T const*>(w.p_); 111   6 auto const& t = *reinterpret_cast<T const*>(w.p_);
112   112  
113   #if defined(__clang__) 113   #if defined(__clang__)
114   # pragma clang diagnostic push 114   # pragma clang diagnostic push
115   # pragma clang diagnostic ignored "-Wsign-compare" 115   # pragma clang diagnostic ignored "-Wsign-compare"
116   #elif defined(__GNUC__) 116   #elif defined(__GNUC__)
117   # pragma GCC diagnostic push 117   # pragma GCC diagnostic push
118   # pragma GCC diagnostic ignored "-Wsign-compare" 118   # pragma GCC diagnostic ignored "-Wsign-compare"
119   #elif defined(_MSC_VER) 119   #elif defined(_MSC_VER)
120   # pragma warning( push ) 120   # pragma warning( push )
121   # pragma warning( disable : 4018 ) 121   # pragma warning( disable : 4018 )
122   # pragma warning( disable : 4127 ) 122   # pragma warning( disable : 4127 )
123   #endif 123   #endif
124   124  
HITCBC 125   134 if( t < 0 ) 125   134 if( t < 0 )
126   { 126   {
127   // T is obviously signed, so this comparison is safe 127   // T is obviously signed, so this comparison is safe
HITCBC 128   6 if( t >= (std::numeric_limits<std::int64_t>::min)() ) 128   6 if( t >= (std::numeric_limits<std::int64_t>::min)() )
129   { 129   {
HITCBC 130   6 std::int64_t i = t; 130   6 std::int64_t i = t;
HITCBC 131   6 return write_int64(w, ss0, i); 131   6 return write_int64(w, ss0, i);
132   } 132   }
133   } 133   }
HITCBC 134   334 else if( t <= (std::numeric_limits<std::uint64_t>::max)() ) 134   334 else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
135   { 135   {
HITCBC 136   334 std::uint64_t u = t; 136   334 std::uint64_t u = t;
HITCBC 137   334 return write_uint64(w, ss0, u); 137   334 return write_uint64(w, ss0, u);
138   } 138   }
139   #if defined(__clang__) 139   #if defined(__clang__)
140   # pragma clang diagnostic pop 140   # pragma clang diagnostic pop
141   #elif defined(__GNUC__) 141   #elif defined(__GNUC__)
142   # pragma GCC diagnostic pop 142   # pragma GCC diagnostic pop
143   #elif defined(_MSC_VER) 143   #elif defined(_MSC_VER)
144   # pragma warning( pop ) 144   # pragma warning( pop )
145   #endif 145   #endif
146   146  
147   #if defined(_MSC_VER) 147   #if defined(_MSC_VER)
148   # pragma warning( push ) 148   # pragma warning( push )
149   # pragma warning( disable : 4244 ) 149   # pragma warning( disable : 4244 )
150   #endif 150   #endif
MISUBC 151   double d = t; 151   double d = t;
MISUBC 152   return write_double(w, ss0, d); 152   return write_double(w, ss0, d);
153   #if defined(_MSC_VER) 153   #if defined(_MSC_VER)
154   # pragma warning( pop ) 154   # pragma warning( pop )
155   #endif 155   #endif
156   } 156   }
157   157  
HITCBC 158   66 return resume_buffer(w, ss0); 158   66 return resume_buffer(w, ss0);
159   } 159   }
160   160  
161   template<class T, bool StackEmpty> 161   template<class T, bool StackEmpty>
162   BOOST_FORCEINLINE 162   BOOST_FORCEINLINE
163   bool 163   bool
164   write_impl(floating_point_conversion_tag, writer& w, stream& ss0) 164   write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
165   { 165   {
166   #if defined(_MSC_VER) 166   #if defined(_MSC_VER)
167   # pragma warning( push ) 167   # pragma warning( push )
168   # pragma warning( disable : 4127 ) 168   # pragma warning( disable : 4127 )
169   #endif 169   #endif
HITCBC 170   10 if( StackEmpty || w.st_.empty() ) 170   10 if( StackEmpty || w.st_.empty() )
171   #if defined(_MSC_VER) 171   #if defined(_MSC_VER)
172   # pragma warning( pop ) 172   # pragma warning( pop )
173   #endif 173   #endif
174   { 174   {
HITCBC 175   10 double d = *reinterpret_cast<T const*>(w.p_); 175   10 double d = *reinterpret_cast<T const*>(w.p_);
HITCBC 176   10 return write_double(w, ss0, d); 176   10 return write_double(w, ss0, d);
177   } 177   }
178   178  
HITCBC 179   10 return resume_buffer(w, ss0); 179   10 return resume_buffer(w, ss0);
180   } 180   }
181   181  
182   template<class T, bool StackEmpty> 182   template<class T, bool StackEmpty>
183   BOOST_FORCEINLINE 183   BOOST_FORCEINLINE
184   bool 184   bool
185   write_impl(string_like_conversion_tag, writer& w, stream& ss0) 185   write_impl(string_like_conversion_tag, writer& w, stream& ss0)
186   { 186   {
187   #if defined(_MSC_VER) 187   #if defined(_MSC_VER)
188   # pragma warning( push ) 188   # pragma warning( push )
189   # pragma warning( disable : 4127 ) 189   # pragma warning( disable : 4127 )
190   #endif 190   #endif
HITCBC 191   112 if( StackEmpty || w.st_.empty() ) 191   112 if( StackEmpty || w.st_.empty() )
192   #if defined(_MSC_VER) 192   #if defined(_MSC_VER)
193   # pragma warning( pop ) 193   # pragma warning( pop )
194   #endif 194   #endif
195   { 195   {
MISUBC 196   string_view const sv = *reinterpret_cast<T const*>(w.p_); 196   string_view const sv = *reinterpret_cast<T const*>(w.p_);
HITCBC 197   91 w.cs0_ = { sv.data(), sv.size() }; 197   91 w.cs0_ = { sv.data(), sv.size() };
HITGNC   198 + 91 w.buf_[2] = false;
HITCBC 198   91 return write_string(w, ss0); 199   91 return write_string(w, ss0);
199   } 200   }
200   201  
HITCBC 201   112 return resume_string(w, ss0); 202   112 return resume_string(w, ss0);
202   } 203   }
203   204  
204   template<class T, bool StackEmpty> 205   template<class T, bool StackEmpty>
205   BOOST_FORCEINLINE 206   BOOST_FORCEINLINE
206   bool 207   bool
207   write_impl(sequence_conversion_tag, writer& w, stream& ss0) 208   write_impl(sequence_conversion_tag, writer& w, stream& ss0)
208   { 209   {
209   using It = iterator_type<T const>; 210   using It = iterator_type<T const>;
210   using Elem = value_type<T>; 211   using Elem = value_type<T>;
211   212  
212   T const* pt; 213   T const* pt;
HITCBC 213   6078 local_stream ss(ss0); 214   6125 local_stream ss(ss0);
HITCBC 214   37 It it; 215   37 It it;
HITCBC 215   17 It end; 216   17 It end;
216   #if defined(_MSC_VER) 217   #if defined(_MSC_VER)
217   # pragma warning( push ) 218   # pragma warning( push )
218   # pragma warning( disable : 4127 ) 219   # pragma warning( disable : 4127 )
219   #endif 220   #endif
HITCBC 220   2656 if(StackEmpty || w.st_.empty()) 221   2684 if(StackEmpty || w.st_.empty())
221   { 222   {
222   #if defined(_MSC_VER) 223   #if defined(_MSC_VER)
223   # pragma warning( pop ) 224   # pragma warning( pop )
224   #endif 225   #endif
HITCBC 225   3422 BOOST_ASSERT( w.p_ ); 226   3441 BOOST_ASSERT( w.p_ );
HITCBC 226   3422 pt = reinterpret_cast<T const*>(w.p_); 227   3441 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 227   3422 it = std::begin(*pt); 228   3441 it = std::begin(*pt);
HITCBC 228   6844 end = std::end(*pt); 229   6882 end = std::end(*pt);
229   } 230   }
230   else 231   else
231   { 232   {
232   writer::state st; 233   writer::state st;
HITCBC 233   2656 w.st_.pop(st); 234   2684 w.st_.pop(st);
HITCBC 234   2656 w.st_.pop(it); 235   2684 w.st_.pop(it);
HITCBC 235   2656 w.st_.pop(pt); 236   2684 w.st_.pop(pt);
HITCBC 236   2656 end = std::end(*pt); 237   2684 end = std::end(*pt);
HITCBC 237   2656 switch(st) 238   2684 switch(st)
238   { 239   {
HITCBC 239   70 default: 240   70 default:
HITCBC 240   70 case writer::state::arr1: goto do_arr1; 241   70 case writer::state::arr1: goto do_arr1;
HITCBC 241   2314 case writer::state::arr2: goto do_arr2; 242   2338 case writer::state::arr2: goto do_arr2;
HITCBC 242   40 case writer::state::arr3: goto do_arr3; 243   42 case writer::state::arr3: goto do_arr3;
HITCBC 243   232 case writer::state::arr4: goto do_arr4; 244   234 case writer::state::arr4: goto do_arr4;
244   break; 245   break;
245   } 246   }
246   } 247   }
HITCBC 247   3492 do_arr1: 248   3511 do_arr1:
HITCBC 248   3492 if(BOOST_JSON_LIKELY(ss)) 249   3511 if(BOOST_JSON_LIKELY(ss))
HITCBC 249   3422 ss.append('['); 250   3441 ss.append('[');
250   else 251   else
HITCBC 251   70 return w.suspend(writer::state::arr1, it, pt); 252   70 return w.suspend(writer::state::arr1, it, pt);
HITCBC 252   3422 if(it == end) 253   3441 if(it == end)
HITCBC 253   507 goto do_arr4; 254   507 goto do_arr4;
254   for(;;) 255   for(;;)
255   { 256   {
HITCBC 256   4064 w.p_ = std::addressof(*it); 257   4102 w.p_ = std::addressof(*it);
HITCBC 257   6378 do_arr2: 258   6440 do_arr2:
HITCBC 258   6378 if( !write_impl<Elem, StackEmpty>(w, ss) ) 259   6440 if( !write_impl<Elem, StackEmpty>(w, ss) )
HITCBC 259   2315 return w.suspend(writer::state::arr2, it, pt); 260   2339 return w.suspend(writer::state::arr2, it, pt);
HITCBC 260   4063 if(BOOST_JSON_UNLIKELY( ++it == end )) 261   4101 if(BOOST_JSON_UNLIKELY( ++it == end ))
HITCBC 261   2914 break; 262   2933 break;
HITCBC 262   1149 do_arr3: 263   1168 do_arr3:
HITCBC 263   1189 if(BOOST_JSON_LIKELY(ss)) 264   1210 if(BOOST_JSON_LIKELY(ss))
HITCBC 264   1149 ss.append(','); 265   1168 ss.append(',');
265   else 266   else
HITCBC 266   40 return w.suspend(writer::state::arr3, it, pt); 267   42 return w.suspend(writer::state::arr3, it, pt);
267   } 268   }
HITCBC 268   3653 do_arr4: 269   3674 do_arr4:
HITCBC 269   3653 if(BOOST_JSON_LIKELY(ss)) 270   3674 if(BOOST_JSON_LIKELY(ss))
HITCBC 270   3421 ss.append(']'); 271   3440 ss.append(']');
271   else 272   else
HITCBC 272   232 return w.suspend(writer::state::arr4, it, pt); 273   234 return w.suspend(writer::state::arr4, it, pt);
HITCBC 273   3421 return true; 274   3440 return true;
HITCBC 274   6078 } 275   6125 }
275   276  
276   template<class T, bool StackEmpty> 277   template<class T, bool StackEmpty>
277   BOOST_FORCEINLINE 278   BOOST_FORCEINLINE
278   bool 279   bool
279   write_impl(map_like_conversion_tag, writer& w, stream& ss0) 280   write_impl(map_like_conversion_tag, writer& w, stream& ss0)
280   { 281   {
281   using It = iterator_type<T const>; 282   using It = iterator_type<T const>;
282   using Mapped = mapped_type<T>; 283   using Mapped = mapped_type<T>;
283   284  
284   T const* pt; 285   T const* pt;
HITCBC 285   27290 local_stream ss(ss0); 286   27361 local_stream ss(ss0);
HITCBC 286   96 It it; 287   96 It it;
HITCBC 287   96 It end; 288   96 It end;
288   #if defined(_MSC_VER) 289   #if defined(_MSC_VER)
289   # pragma warning( push ) 290   # pragma warning( push )
290   # pragma warning( disable : 4127 ) 291   # pragma warning( disable : 4127 )
291   #endif 292   #endif
HITCBC 292   9120 if(StackEmpty || w.st_.empty()) 293   9164 if(StackEmpty || w.st_.empty())
293   #if defined(_MSC_VER) 294   #if defined(_MSC_VER)
294   # pragma warning( pop ) 295   # pragma warning( pop )
295   #endif 296   #endif
296   { 297   {
HITCBC 297   18170 BOOST_ASSERT( w.p_ ); 298   18197 BOOST_ASSERT( w.p_ );
HITCBC 298   18170 pt = reinterpret_cast<T const*>(w.p_); 299   18197 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 299   18170 it = std::begin(*pt); 300   18197 it = std::begin(*pt);
HITCBC 300   36340 end = std::end(*pt); 301   36394 end = std::end(*pt);
301   } 302   }
302   else 303   else
303   { 304   {
304   writer::state st; 305   writer::state st;
HITCBC 305   9120 w.st_.pop(st); 306   9164 w.st_.pop(st);
HITCBC 306   9120 w.st_.pop(it); 307   9164 w.st_.pop(it);
HITCBC 307   9120 w.st_.pop(pt); 308   9164 w.st_.pop(pt);
HITCBC 308   9120 end = std::end(*pt); 309   9164 end = std::end(*pt);
HITCBC 309   9120 switch(st) 310   9164 switch(st)
310   { 311   {
HITCBC 311   12 default: 312   12 default:
HITCBC 312   12 case writer::state::obj1: goto do_obj1; 313   12 case writer::state::obj1: goto do_obj1;
HITCBC 313   296 case writer::state::obj2: goto do_obj2; 314   308 case writer::state::obj2: goto do_obj2;
HITCBC 314   50 case writer::state::obj3: goto do_obj3; 315   54 case writer::state::obj3: goto do_obj3;
HITCBC 315   8700 case writer::state::obj4: goto do_obj4; 316   8724 case writer::state::obj4: goto do_obj4;
HITCBC 316   16 case writer::state::obj5: goto do_obj5; 317   18 case writer::state::obj5: goto do_obj5;
HITCBC 317   46 case writer::state::obj6: goto do_obj6; 318   48 case writer::state::obj6: goto do_obj6;
318   break; 319   break;
319   } 320   }
320   } 321   }
HITCBC 321   18182 do_obj1: 322   18209 do_obj1:
HITCBC 322   18182 if(BOOST_JSON_LIKELY( ss )) 323   18209 if(BOOST_JSON_LIKELY( ss ))
HITCBC 323   18170 ss.append('{'); 324   18197 ss.append('{');
324   else 325   else
HITCBC 325   12 return w.suspend(writer::state::obj1, it, pt); 326   12 return w.suspend(writer::state::obj1, it, pt);
HITCBC 326   18170 if(BOOST_JSON_UNLIKELY( it == end )) 327   18197 if(BOOST_JSON_UNLIKELY( it == end ))
HITCBC 327   563 goto do_obj6; 328   563 goto do_obj6;
HITCBC 328   2129 for(;;) 329   2156 for(;;)
329   { 330   {
330   { 331   {
331   using std::get; 332   using std::get;
HITCBC 332   19736 string_view const sv = get<0>(*it); 333   19790 string_view const sv = get<0>(*it);
HITCBC 333   19736 w.cs0_ = { sv.data(), sv.size() }; 334   19790 w.cs0_ = { sv.data(), sv.size() };
HITGNC   335 + 19790 w.buf_[2] = false;
334   } 336   }
335   if( true ) 337   if( true )
336   { 338   {
HITCBC 337   19736 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) )) 339   19790 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
HITCBC 338   173 return w.suspend(writer::state::obj2, it, pt); 340   181 return w.suspend(writer::state::obj2, it, pt);
339   } 341   }
340   else 342   else
341   { 343   {
HITCBC 342   296 do_obj2: 344   308 do_obj2:
HITCBC 343   296 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) )) 345   308 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
HITCBC 344   123 return w.suspend(writer::state::obj2, it, pt); 346   127 return w.suspend(writer::state::obj2, it, pt);
345   } 347   }
HITCBC 346   173 do_obj3: 348   181 do_obj3:
HITCBC 347   19786 if(BOOST_JSON_LIKELY(ss)) 349   19844 if(BOOST_JSON_LIKELY(ss))
HITCBC 348   19736 ss.append(':'); 350   19790 ss.append(':');
349   else 351   else
HITCBC 350   50 return w.suspend(writer::state::obj3, it, pt); 352   54 return w.suspend(writer::state::obj3, it, pt);
HITCBC 351   28436 do_obj4: 353   28514 do_obj4:
352   { 354   {
353   using std::get; 355   using std::get;
HITCBC 354   28436 w.p_ = std::addressof( get<1>(*it) ); 356   28514 w.p_ = std::addressof( get<1>(*it) );
355   } 357   }
HITCBC 356   28436 if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) ))) 358   28514 if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
HITCBC 357   8700 return w.suspend(writer::state::obj4, it, pt); 359   8724 return w.suspend(writer::state::obj4, it, pt);
HITCBC 358   19736 ++it; 360   19790 ++it;
HITCBC 359   19736 if(BOOST_JSON_UNLIKELY(it == end)) 361   19790 if(BOOST_JSON_UNLIKELY(it == end))
HITCBC 360   17607 break; 362   17634 break;
HITCBC 361   2129 do_obj5: 363   2156 do_obj5:
HITCBC 362   2145 if(BOOST_JSON_LIKELY(ss)) 364   2174 if(BOOST_JSON_LIKELY(ss))
HITCBC 363   2129 ss.append(','); 365   2156 ss.append(',');
364   else 366   else
HITCBC 365   16 return w.suspend(writer::state::obj5, it, pt); 367   18 return w.suspend(writer::state::obj5, it, pt);
366   } 368   }
HITCBC 367   18216 do_obj6: 369   18245 do_obj6:
HITCBC 368   18216 if(BOOST_JSON_LIKELY( ss )) 370   18245 if(BOOST_JSON_LIKELY( ss ))
369   { 371   {
HITCBC 370   18170 ss.append('}'); 372   18197 ss.append('}');
HITCBC 371   18170 return true; 373   18197 return true;
372   } 374   }
HITCBC 373   46 return w.suspend(writer::state::obj6, it, pt); 375   48 return w.suspend(writer::state::obj6, it, pt);
HITCBC 374   27290 } 376   27361 }
375   377  
376   template< class T, bool StackEmpty > 378   template< class T, bool StackEmpty >
377   struct serialize_tuple_elem_helper 379   struct serialize_tuple_elem_helper
378   { 380   {
379   writer& w; 381   writer& w;
380   stream& ss; 382   stream& ss;
381   T const* pt; 383   T const* pt;
382   384  
383   template< std::size_t I > 385   template< std::size_t I >
384   bool 386   bool
HITCBC 385   258 operator()( std::integral_constant<std::size_t, I> ) const 387   258 operator()( std::integral_constant<std::size_t, I> ) const
386   { 388   {
387   using std::get; 389   using std::get;
HITCBC 388   258 w.p_ = std::addressof( get<I>(*pt) ); 390   258 w.p_ = std::addressof( get<I>(*pt) );
389   391  
390   using Elem = tuple_element_t<I, T>; 392   using Elem = tuple_element_t<I, T>;
HITCBC 391   258 return write_impl<Elem, StackEmpty>(w, ss); 393   258 return write_impl<Elem, StackEmpty>(w, ss);
392   } 394   }
393   }; 395   };
394   396  
395   template<class T, bool StackEmpty> 397   template<class T, bool StackEmpty>
396   BOOST_FORCEINLINE 398   BOOST_FORCEINLINE
397   bool 399   bool
398   write_impl(tuple_conversion_tag, writer& w, stream& ss0) 400   write_impl(tuple_conversion_tag, writer& w, stream& ss0)
399   { 401   {
400   T const* pt; 402   T const* pt;
HITCBC 401   174 local_stream ss(ss0); 403   174 local_stream ss(ss0);
402   std::size_t cur; 404   std::size_t cur;
HITCBC 403   64 constexpr std::size_t N = std::tuple_size<T>::value; 405   64 constexpr std::size_t N = std::tuple_size<T>::value;
404   #if defined(_MSC_VER) 406   #if defined(_MSC_VER)
405   # pragma warning( push ) 407   # pragma warning( push )
406   # pragma warning( disable : 4127 ) 408   # pragma warning( disable : 4127 )
407   #endif 409   #endif
HITCBC 408   110 if(StackEmpty || w.st_.empty()) 410   110 if(StackEmpty || w.st_.empty())
409   { 411   {
410   #if defined(_MSC_VER) 412   #if defined(_MSC_VER)
411   # pragma warning( pop ) 413   # pragma warning( pop )
412   #endif 414   #endif
HITCBC 413   76 BOOST_ASSERT( w.p_ ); 415   76 BOOST_ASSERT( w.p_ );
HITCBC 414   76 pt = reinterpret_cast<T const*>(w.p_); 416   76 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 415   76 cur = 0; 417   76 cur = 0;
416   } 418   }
417   else 419   else
418   { 420   {
419   writer::state st; 421   writer::state st;
HITCBC 420   98 w.st_.pop(st); 422   98 w.st_.pop(st);
HITCBC 421   98 w.st_.pop(cur); 423   98 w.st_.pop(cur);
HITCBC 422   98 w.st_.pop(pt); 424   98 w.st_.pop(pt);
HITCBC 423   98 switch(st) 425   98 switch(st)
424   { 426   {
HITCBC 425   2 default: 427   2 default:
HITCBC 426   2 case writer::state::arr1: goto do_arr1; 428   2 case writer::state::arr1: goto do_arr1;
HITCBC 427   82 case writer::state::arr2: goto do_arr2; 429   82 case writer::state::arr2: goto do_arr2;
HITCBC 428   8 case writer::state::arr3: goto do_arr3; 430   8 case writer::state::arr3: goto do_arr3;
HITCBC 429   6 case writer::state::arr4: goto do_arr4; 431   6 case writer::state::arr4: goto do_arr4;
430   break; 432   break;
431   } 433   }
432   } 434   }
HITCBC 433   78 do_arr1: 435   78 do_arr1:
HITCBC 434   78 if(BOOST_JSON_LIKELY(ss)) 436   78 if(BOOST_JSON_LIKELY(ss))
HITCBC 435   76 ss.append('['); 437   76 ss.append('[');
436   else 438   else
HITCBC 437   2 return w.suspend(writer::state::arr1, cur, pt); 439   2 return w.suspend(writer::state::arr1, cur, pt);
HITCBC 438   100 for(;;) 440   100 for(;;)
439   { 441   {
HITCBC 440   258 do_arr2: 442   258 do_arr2:
441   { 443   {
HITCBC 442   258 bool const stop = !mp11::mp_with_index<N>( 444   258 bool const stop = !mp11::mp_with_index<N>(
443   cur, 445   cur,
444   serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt}); 446   serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
HITCBC 445   258 if(BOOST_JSON_UNLIKELY( stop )) 447   258 if(BOOST_JSON_UNLIKELY( stop ))
HITCBC 446   82 return w.suspend(writer::state::arr2, cur, pt); 448   82 return w.suspend(writer::state::arr2, cur, pt);
447   } 449   }
HITCBC 448   176 if(BOOST_JSON_UNLIKELY( ++cur == N )) 450   176 if(BOOST_JSON_UNLIKELY( ++cur == N ))
HITCBC 449   76 break; 451   76 break;
HITCBC 450   100 do_arr3: 452   100 do_arr3:
HITCBC 451   108 if(BOOST_JSON_LIKELY(ss)) 453   108 if(BOOST_JSON_LIKELY(ss))
HITCBC 452   100 ss.append(','); 454   100 ss.append(',');
453   else 455   else
HITCBC 454   8 return w.suspend(writer::state::arr3, cur, pt); 456   8 return w.suspend(writer::state::arr3, cur, pt);
455   } 457   }
HITCBC 456   82 do_arr4: 458   82 do_arr4:
HITCBC 457   82 if(BOOST_JSON_LIKELY(ss)) 459   82 if(BOOST_JSON_LIKELY(ss))
HITCBC 458   76 ss.append(']'); 460   76 ss.append(']');
459   else 461   else
HITCBC 460   6 return w.suspend(writer::state::arr4, cur, pt); 462   6 return w.suspend(writer::state::arr4, cur, pt);
HITCBC 461   76 return true; 463   76 return true;
HITCBC 462   174 } 464   174 }
463   465  
464   template< class T, bool StackEmpty > 466   template< class T, bool StackEmpty >
465   struct serialize_struct_elem_helper 467   struct serialize_struct_elem_helper
466   { 468   {
467   static_assert( 469   static_assert(
468   uniquely_named_members<T>::value, 470   uniquely_named_members<T>::value,
469   "The type has several described members with the same name."); 471   "The type has several described members with the same name.");
470   472  
471   writer& w; 473   writer& w;
472   local_stream& ss; 474   local_stream& ss;
473   T const* pt; 475   T const* pt;
474   writer::state st; 476   writer::state st;
475   477  
476   template< std::size_t I > 478   template< std::size_t I >
477   writer::state 479   writer::state
478   operator()( std::integral_constant<std::size_t, I> ) const 480   operator()( std::integral_constant<std::size_t, I> ) const
479   { 481   {
480   using Ds = described_members<T>; 482   using Ds = described_members<T>;
481   using D = mp11::mp_at_c<Ds, I>; 483   using D = mp11::mp_at_c<Ds, I>;
482   using M = described_member_t<T, D>; 484   using M = described_member_t<T, D>;
483   485  
484   switch(st) 486   switch(st)
485   { 487   {
486   case writer::state::obj2: goto do_obj2; 488   case writer::state::obj2: goto do_obj2;
487   case writer::state::obj3: goto do_obj3; 489   case writer::state::obj3: goto do_obj3;
488   case writer::state::obj4: goto do_obj4; 490   case writer::state::obj4: goto do_obj4;
489   default: break; 491   default: break;
490   } 492   }
491   493  
492   { 494   {
493   string_view const sv = D::name; 495   string_view const sv = D::name;
494   w.cs0_ = { sv.data(), sv.size() }; 496   w.cs0_ = { sv.data(), sv.size() };
  497 + w.buf_[2] = false;
495   } 498   }
496   if( true ) 499   if( true )
497   { 500   {
498   if(BOOST_JSON_UNLIKELY( !write_string(w, ss) )) 501   if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
499   return writer::state::obj2; 502   return writer::state::obj2;
500   } 503   }
501   else 504   else
502   { 505   {
503   do_obj2: 506   do_obj2:
504   if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) )) 507   if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
505   return writer::state::obj2; 508   return writer::state::obj2;
506   } 509   }
507   do_obj3: 510   do_obj3:
508   if(BOOST_JSON_LIKELY(ss)) 511   if(BOOST_JSON_LIKELY(ss))
509   ss.append(':'); 512   ss.append(':');
510   else 513   else
511   return writer::state::obj3; 514   return writer::state::obj3;
512   do_obj4: 515   do_obj4:
513   w.p_ = std::addressof( pt->* D::pointer ); 516   w.p_ = std::addressof( pt->* D::pointer );
514   if(BOOST_JSON_UNLIKELY(( 517   if(BOOST_JSON_UNLIKELY((
515   !write_impl<M, StackEmpty>(w, ss) ))) 518   !write_impl<M, StackEmpty>(w, ss) )))
516   return writer::state::obj4; 519   return writer::state::obj4;
517   520  
518   return writer::state{}; 521   return writer::state{};
519   } 522   }
520   }; 523   };
521   524  
522   template<class T, bool StackEmpty> 525   template<class T, bool StackEmpty>
523   BOOST_FORCEINLINE 526   BOOST_FORCEINLINE
524   bool 527   bool
525   write_impl(described_class_conversion_tag, writer& w, stream& ss0) 528   write_impl(described_class_conversion_tag, writer& w, stream& ss0)
526   { 529   {
527   using Ds = described_members<T>; 530   using Ds = described_members<T>;
528   531  
529   T const* pt; 532   T const* pt;
530   local_stream ss(ss0); 533   local_stream ss(ss0);
531   std::size_t cur; 534   std::size_t cur;
532   constexpr std::size_t N = mp11::mp_size<Ds>::value; 535   constexpr std::size_t N = mp11::mp_size<Ds>::value;
533   writer::state st; 536   writer::state st;
534   #if defined(_MSC_VER) 537   #if defined(_MSC_VER)
535   # pragma warning( push ) 538   # pragma warning( push )
536   # pragma warning( disable : 4127 ) 539   # pragma warning( disable : 4127 )
537   #endif 540   #endif
538   if(StackEmpty || w.st_.empty()) 541   if(StackEmpty || w.st_.empty())
539   #if defined(_MSC_VER) 542   #if defined(_MSC_VER)
540   # pragma warning( pop ) 543   # pragma warning( pop )
541   #endif 544   #endif
542   { 545   {
543   BOOST_ASSERT( w.p_ ); 546   BOOST_ASSERT( w.p_ );
544   pt = reinterpret_cast<T const*>(w.p_); 547   pt = reinterpret_cast<T const*>(w.p_);
545   cur = 0; 548   cur = 0;
546   } 549   }
547   else 550   else
548   { 551   {
549   w.st_.pop(st); 552   w.st_.pop(st);
550   w.st_.pop(cur); 553   w.st_.pop(cur);
551   w.st_.pop(pt); 554   w.st_.pop(pt);
552   switch(st) 555   switch(st)
553   { 556   {
554   default: 557   default:
555   case writer::state::obj1: goto do_obj1; 558   case writer::state::obj1: goto do_obj1;
556   case writer::state::obj2: // fall through 559   case writer::state::obj2: // fall through
557   case writer::state::obj3: // fall through 560   case writer::state::obj3: // fall through
558   case writer::state::obj4: goto do_obj2; 561   case writer::state::obj4: goto do_obj2;
559   case writer::state::obj5: goto do_obj5; 562   case writer::state::obj5: goto do_obj5;
560   case writer::state::obj6: goto do_obj6; 563   case writer::state::obj6: goto do_obj6;
561   break; 564   break;
562   } 565   }
563   } 566   }
564   do_obj1: 567   do_obj1:
565   if(BOOST_JSON_LIKELY( ss )) 568   if(BOOST_JSON_LIKELY( ss ))
566   ss.append('{'); 569   ss.append('{');
567   else 570   else
568   return w.suspend(writer::state::obj1, cur, pt); 571   return w.suspend(writer::state::obj1, cur, pt);
569   if(BOOST_JSON_UNLIKELY( cur == N )) 572   if(BOOST_JSON_UNLIKELY( cur == N ))
570   goto do_obj6; 573   goto do_obj6;
571   for(;;) 574   for(;;)
572   { 575   {
573   st = {}; 576   st = {};
574   do_obj2: 577   do_obj2:
575   st = mp11::mp_with_index<N>( 578   st = mp11::mp_with_index<N>(
576   cur, 579   cur,
577   serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st}); 580   serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
578   if(BOOST_JSON_UNLIKELY( st != writer::state{} )) 581   if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
579   return w.suspend(st, cur, pt); 582   return w.suspend(st, cur, pt);
580   ++cur; 583   ++cur;
581   if(BOOST_JSON_UNLIKELY(cur == N)) 584   if(BOOST_JSON_UNLIKELY(cur == N))
582   break; 585   break;
583   do_obj5: 586   do_obj5:
584   if(BOOST_JSON_LIKELY(ss)) 587   if(BOOST_JSON_LIKELY(ss))
585   ss.append(','); 588   ss.append(',');
586   else 589   else
587   return w.suspend(writer::state::obj5, cur, pt); 590   return w.suspend(writer::state::obj5, cur, pt);
588   } 591   }
589   do_obj6: 592   do_obj6:
590   if(BOOST_JSON_LIKELY( ss )) 593   if(BOOST_JSON_LIKELY( ss ))
591   { 594   {
592   ss.append('}'); 595   ss.append('}');
593   return true; 596   return true;
594   } 597   }
595   return w.suspend(writer::state::obj6, cur, pt); 598   return w.suspend(writer::state::obj6, cur, pt);
596   } 599   }
597   600  
598   template<class T, bool StackEmpty> 601   template<class T, bool StackEmpty>
599   BOOST_FORCEINLINE 602   BOOST_FORCEINLINE
600   bool 603   bool
601   write_impl(described_enum_conversion_tag, writer& w, stream& ss) 604   write_impl(described_enum_conversion_tag, writer& w, stream& ss)
602   { 605   {
603   #ifdef BOOST_DESCRIBE_CXX14 606   #ifdef BOOST_DESCRIBE_CXX14
604   using Integer = typename std::underlying_type<T>::type; 607   using Integer = typename std::underlying_type<T>::type;
605   608  
606   #if defined(_MSC_VER) 609   #if defined(_MSC_VER)
607   # pragma warning( push ) 610   # pragma warning( push )
608   # pragma warning( disable : 4127 ) 611   # pragma warning( disable : 4127 )
609   #endif 612   #endif
610   if(StackEmpty || w.st_.empty()) 613   if(StackEmpty || w.st_.empty())
611   #if defined(_MSC_VER) 614   #if defined(_MSC_VER)
612   # pragma warning( pop ) 615   # pragma warning( pop )
613   #endif 616   #endif
614   { 617   {
615   BOOST_ASSERT( w.p_ ); 618   BOOST_ASSERT( w.p_ );
616   T const* pt = reinterpret_cast<T const*>(w.p_); 619   T const* pt = reinterpret_cast<T const*>(w.p_);
617   char const* const name = describe::enum_to_string(*pt, nullptr); 620   char const* const name = describe::enum_to_string(*pt, nullptr);
618   if( name ) 621   if( name )
619   { 622   {
620   string_view const sv = name; 623   string_view const sv = name;
621   w.cs0_ = { sv.data(), sv.size() }; 624   w.cs0_ = { sv.data(), sv.size() };
  625 + w.buf_[2] = false;
622   return write_string(w, ss); 626   return write_string(w, ss);
623   } 627   }
624   else 628   else
625   { 629   {
626   Integer n = static_cast<Integer>(*pt); 630   Integer n = static_cast<Integer>(*pt);
627   w.p_ = &n; 631   w.p_ = &n;
628   return write_impl<Integer, true>(w, ss); 632   return write_impl<Integer, true>(w, ss);
629   } 633   }
630   } 634   }
631   else 635   else
632   { 636   {
633   writer::state st; 637   writer::state st;
634   w.st_.peek(st); 638   w.st_.peek(st);
635   if( st == writer::state::lit ) 639   if( st == writer::state::lit )
636   return write_impl<Integer, false>(w, ss); 640   return write_impl<Integer, false>(w, ss);
637   else 641   else
638   return resume_string(w, ss); 642   return resume_string(w, ss);
639   } 643   }
640   #else // BOOST_DESCRIBE_CXX14 644   #else // BOOST_DESCRIBE_CXX14
641   (void)w; 645   (void)w;
642   (void)ss; 646   (void)ss;
643   static_assert( 647   static_assert(
644   !std::is_same<T, T>::value, 648   !std::is_same<T, T>::value,
645   "described enums require C++14 support"); 649   "described enums require C++14 support");
646   return false; 650   return false;
647   #endif // BOOST_DESCRIBE_CXX14 651   #endif // BOOST_DESCRIBE_CXX14
648   } 652   }
649   653  
650   template< class T, bool StackEmpty > 654   template< class T, bool StackEmpty >
651   struct serialize_variant_elem_helper 655   struct serialize_variant_elem_helper
652   { 656   {
653   writer& w; 657   writer& w;
654   stream& ss; 658   stream& ss;
655   659  
656   template<class Elem> 660   template<class Elem>
657   bool 661   bool
658   operator()(Elem const& x) const 662   operator()(Elem const& x) const
659   { 663   {
660   w.p_ = std::addressof(x); 664   w.p_ = std::addressof(x);
661   return write_impl<Elem, true>(w, ss); 665   return write_impl<Elem, true>(w, ss);
662   } 666   }
663   }; 667   };
664   668  
665   template< class T > 669   template< class T >
666   struct serialize_variant_elem_helper<T, false> 670   struct serialize_variant_elem_helper<T, false>
667   { 671   {
668   writer& w; 672   writer& w;
669   stream& ss; 673   stream& ss;
670   674  
671   template< std::size_t I > 675   template< std::size_t I >
672   bool 676   bool
673   operator()( std::integral_constant<std::size_t, I> ) const 677   operator()( std::integral_constant<std::size_t, I> ) const
674   { 678   {
675   using std::get; 679   using std::get;
676   using Elem = remove_cvref<decltype(get<I>( 680   using Elem = remove_cvref<decltype(get<I>(
677   std::declval<T const&>() ))>; 681   std::declval<T const&>() ))>;
678   return write_impl<Elem, false>(w, ss); 682   return write_impl<Elem, false>(w, ss);
679   } 683   }
680   }; 684   };
681   685  
682   template<class T, bool StackEmpty> 686   template<class T, bool StackEmpty>
683   BOOST_FORCEINLINE 687   BOOST_FORCEINLINE
684   bool 688   bool
685   write_impl(variant_conversion_tag, writer& w, stream& ss) 689   write_impl(variant_conversion_tag, writer& w, stream& ss)
686   { 690   {
687   T const* pt; 691   T const* pt;
688   692  
689   using Index = remove_cvref<decltype( pt->index() )>; 693   using Index = remove_cvref<decltype( pt->index() )>;
690   694  
691   #if defined(_MSC_VER) 695   #if defined(_MSC_VER)
692   # pragma warning( push ) 696   # pragma warning( push )
693   # pragma warning( disable : 4127 ) 697   # pragma warning( disable : 4127 )
694   #endif 698   #endif
695   if(StackEmpty || w.st_.empty()) 699   if(StackEmpty || w.st_.empty())
696   #if defined(_MSC_VER) 700   #if defined(_MSC_VER)
697   # pragma warning( pop ) 701   # pragma warning( pop )
698   #endif 702   #endif
699   { 703   {
700   BOOST_ASSERT( w.p_ ); 704   BOOST_ASSERT( w.p_ );
701   pt = reinterpret_cast<T const*>(w.p_); 705   pt = reinterpret_cast<T const*>(w.p_);
702   if(BOOST_JSON_LIKELY(( 706   if(BOOST_JSON_LIKELY((
703   visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt)))) 707   visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
704   return true; 708   return true;
705   709  
706   Index const ix = pt->index(); 710   Index const ix = pt->index();
707   w.st_.push(ix); 711   w.st_.push(ix);
708   return false; 712   return false;
709   } 713   }
710   else 714   else
711   { 715   {
712   Index ix; 716   Index ix;
713   w.st_.pop(ix); 717   w.st_.pop(ix);
714   718  
715   constexpr std::size_t N = mp11::mp_size<T>::value; 719   constexpr std::size_t N = mp11::mp_size<T>::value;
716   if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>( 720   if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
717   ix, 721   ix,
718   serialize_variant_elem_helper<T, false>{w, ss})))) 722   serialize_variant_elem_helper<T, false>{w, ss}))))
719   return true; 723   return true;
720   724  
721   w.st_.push(ix); 725   w.st_.push(ix);
722   return false; 726   return false;
723   } 727   }
724   } 728   }
725   729  
726   template<class T, bool StackEmpty> 730   template<class T, bool StackEmpty>
727   BOOST_FORCEINLINE 731   BOOST_FORCEINLINE
728   bool 732   bool
729   write_impl(optional_conversion_tag, writer& w, stream& ss) 733   write_impl(optional_conversion_tag, writer& w, stream& ss)
730   { 734   {
731   using Elem = value_result_type<T>; 735   using Elem = value_result_type<T>;
732   736  
733   bool done; 737   bool done;
734   bool has_value; 738   bool has_value;
735   739  
736   #if defined(_MSC_VER) 740   #if defined(_MSC_VER)
737   # pragma warning( push ) 741   # pragma warning( push )
738   # pragma warning( disable : 4127 ) 742   # pragma warning( disable : 4127 )
739   #endif 743   #endif
740   if(StackEmpty || w.st_.empty()) 744   if(StackEmpty || w.st_.empty())
741   #if defined(_MSC_VER) 745   #if defined(_MSC_VER)
742   # pragma warning( pop ) 746   # pragma warning( pop )
743   #endif 747   #endif
744   { 748   {
745   BOOST_ASSERT( w.p_ ); 749   BOOST_ASSERT( w.p_ );
746   T const* pt = reinterpret_cast<T const*>(w.p_); 750   T const* pt = reinterpret_cast<T const*>(w.p_);
747   has_value = static_cast<bool>(*pt); 751   has_value = static_cast<bool>(*pt);
748   if( has_value ) 752   if( has_value )
749   { 753   {
750   w.p_ = std::addressof( *(*pt) ); 754   w.p_ = std::addressof( *(*pt) );
751   done = write_impl<Elem, true>(w, ss); 755   done = write_impl<Elem, true>(w, ss);
752   } 756   }
753   else 757   else
754   { 758   {
755   w.p_ = nullptr; 759   w.p_ = nullptr;
756   done = write_impl<std::nullptr_t, true>(w, ss);; 760   done = write_impl<std::nullptr_t, true>(w, ss);;
757   } 761   }
758   } 762   }
759   else 763   else
760   { 764   {
761   w.st_.pop(has_value); 765   w.st_.pop(has_value);
762   766  
763   if( has_value ) 767   if( has_value )
764   done = write_impl<Elem, false>(w, ss); 768   done = write_impl<Elem, false>(w, ss);
765   else 769   else
766   done = write_impl<std::nullptr_t, false>(w, ss); 770   done = write_impl<std::nullptr_t, false>(w, ss);
767   } 771   }
768   772  
769   if(BOOST_JSON_UNLIKELY( !done )) 773   if(BOOST_JSON_UNLIKELY( !done ))
770   w.st_.push(has_value); 774   w.st_.push(has_value);
771   775  
772   return done; 776   return done;
773   } 777   }
774   778  
775   template<class T, bool StackEmpty> 779   template<class T, bool StackEmpty>
776   BOOST_FORCEINLINE 780   BOOST_FORCEINLINE
777   bool 781   bool
778   write_impl(path_conversion_tag, writer& w, stream& ss) 782   write_impl(path_conversion_tag, writer& w, stream& ss)
779   { 783   {
  784 + w.buf_[2] = false;
780   #if defined(_MSC_VER) 785   #if defined(_MSC_VER)
781   # pragma warning( push ) 786   # pragma warning( push )
782   # pragma warning( disable : 4127 ) 787   # pragma warning( disable : 4127 )
783   #endif 788   #endif
784   if(StackEmpty || w.st_.empty()) 789   if(StackEmpty || w.st_.empty())
785   #if defined(_MSC_VER) 790   #if defined(_MSC_VER)
786   # pragma warning( pop ) 791   # pragma warning( pop )
787   #endif 792   #endif
788   { 793   {
789   BOOST_ASSERT( w.p_ ); 794   BOOST_ASSERT( w.p_ );
790   T const* pt = reinterpret_cast<T const*>(w.p_); 795   T const* pt = reinterpret_cast<T const*>(w.p_);
791   796  
792   std::string const s = pt->generic_string(); 797   std::string const s = pt->generic_string();
793   w.cs0_ = { s.data(), s.size() }; 798   w.cs0_ = { s.data(), s.size() };
794   if(BOOST_JSON_LIKELY( write_string(w, ss) )) 799   if(BOOST_JSON_LIKELY( write_string(w, ss) ))
795   return true; 800   return true;
796   801  
797   std::size_t const used = w.cs0_.used( s.data() ); 802   std::size_t const used = w.cs0_.used( s.data() );
798   w.st_.push( used ); 803   w.st_.push( used );
799   w.st_.push( std::move(s) ); 804   w.st_.push( std::move(s) );
800   return false; 805   return false;
801   } 806   }
802   else 807   else
803   { 808   {
804   std::string s; 809   std::string s;
805   std::size_t used; 810   std::size_t used;
806   w.st_.pop( s ); 811   w.st_.pop( s );
807   w.st_.pop( used ); 812   w.st_.pop( used );
808   813  
809   w.cs0_ = { s.data(), s.size() }; 814   w.cs0_ = { s.data(), s.size() };
810   w.cs0_.skip(used); 815   w.cs0_.skip(used);
811   816  
812   if(BOOST_JSON_LIKELY( resume_string(w, ss) )) 817   if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
813   return true; 818   return true;
814   819  
815   used = w.cs0_.used( s.data() ); 820   used = w.cs0_.used( s.data() );
816   w.st_.push( used ); 821   w.st_.push( used );
817   w.st_.push( std::move(s) ); 822   w.st_.push( std::move(s) );
818   return false; 823   return false;
819   } 824   }
820   } 825   }
821   826  
822   template<class T, bool StackEmpty> 827   template<class T, bool StackEmpty>
823   bool 828   bool
HITCBC 824   35604 write_impl(writer& w, stream& ss) 829   35744 write_impl(writer& w, stream& ss)
825   { 830   {
826   using cat = detail::generic_conversion_category<T>; 831   using cat = detail::generic_conversion_category<T>;
HITCBC 827   35603 return write_impl<T, StackEmpty>( cat(), w, ss ); 832   35743 return write_impl<T, StackEmpty>( cat(), w, ss );
828   } 833   }
829   834  
830   } // namespace detail 835   } // namespace detail
831   836  
832   template<class T> 837   template<class T>
833   void 838   void
HITCBC 834   219 serializer::reset(T const* p) noexcept 839   219 serializer::reset(T const* p) noexcept
835   { 840   {
836   BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value ); 841   BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
837   BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value ); 842   BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
838   843  
HITCBC 839   219 p_ = p; 844   219 p_ = p;
HITCBC 840   219 fn0_ = &detail::write_impl<T, true>; 845   219 fn0_ = &detail::write_impl<T, true>;
HITCBC 841   219 fn1_ = &detail::write_impl<T, false>; 846   219 fn1_ = &detail::write_impl<T, false>;
HITCBC 842   219 st_.clear(); 847   219 st_.clear();
HITCBC 843   219 done_ = false; 848   219 done_ = false;
HITCBC 844   219 } 849   219 }
845   850  
846   } // namespace json 851   } // namespace json
847   } // namespace boost 852   } // namespace boost
848   853  
849   #endif // BOOST_JSON_IMPL_SERIALIZER_HPP 854   #endif // BOOST_JSON_IMPL_SERIALIZER_HPP