97.80% Lines (178/182) 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   11258 writer::
33   suspend(state st) 33   suspend(state st)
34   { 34   {
HITCBC 35   11258 st_.push(st); 35   11258 st_.push(st);
HITCBC 36   11257 return false; 36   11257 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   11875 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   11875 st_.push(pt);
HITCBC 45   11874 st_.push(u); 45   11874 st_.push(u);
HITCBC 46   11874 st_.push(st); 46   11874 st_.push(st);
HITCBC 47   11874 return false; 47   11874 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_category, 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(boolean_category, 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(integer_category, 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_category, 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_category, 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() };
HITCBC 198   91 return write_string(w, ss0); 198   91 return write_string(w, ss0);
199   } 199   }
200   200  
HITCBC 201   112 return resume_string(w, ss0); 201   112 return resume_string(w, ss0);
202   } 202   }
203   203  
204   template<class T, bool StackEmpty> 204   template<class T, bool StackEmpty>
205   BOOST_FORCEINLINE 205   BOOST_FORCEINLINE
206   bool 206   bool
207 - write_impl(sequence_conversion_tag, writer& w, stream& ss0) 207 + write_impl(sequence_category, writer& w, stream& ss0)
208   { 208   {
209   using It = iterator_type<T const>; 209   using It = iterator_type<T const>;
210   using Elem = value_type<T>; 210   using Elem = value_type<T>;
211   211  
212   T const* pt; 212   T const* pt;
HITCBC 213   6078 local_stream ss(ss0); 213   6078 local_stream ss(ss0);
HITCBC 214   37 It it; 214   37 It it;
HITCBC 215   17 It end; 215   17 It end;
216   #if defined(_MSC_VER) 216   #if defined(_MSC_VER)
217   # pragma warning( push ) 217   # pragma warning( push )
218   # pragma warning( disable : 4127 ) 218   # pragma warning( disable : 4127 )
219   #endif 219   #endif
HITCBC 220   2656 if(StackEmpty || w.st_.empty()) 220   2656 if(StackEmpty || w.st_.empty())
221   { 221   {
222   #if defined(_MSC_VER) 222   #if defined(_MSC_VER)
223   # pragma warning( pop ) 223   # pragma warning( pop )
224   #endif 224   #endif
HITCBC 225   3422 BOOST_ASSERT( w.p_ ); 225   3422 BOOST_ASSERT( w.p_ );
HITCBC 226   3422 pt = reinterpret_cast<T const*>(w.p_); 226   3422 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 227   3422 it = std::begin(*pt); 227   3422 it = std::begin(*pt);
HITCBC 228   6844 end = std::end(*pt); 228   6844 end = std::end(*pt);
229   } 229   }
230   else 230   else
231   { 231   {
232   writer::state st; 232   writer::state st;
HITCBC 233   2656 w.st_.pop(st); 233   2656 w.st_.pop(st);
HITCBC 234   2656 w.st_.pop(it); 234   2656 w.st_.pop(it);
HITCBC 235   2656 w.st_.pop(pt); 235   2656 w.st_.pop(pt);
HITCBC 236   2656 end = std::end(*pt); 236   2656 end = std::end(*pt);
HITCBC 237   2656 switch(st) 237   2656 switch(st)
238   { 238   {
HITCBC 239   70 default: 239   70 default:
HITCBC 240   70 case writer::state::arr1: goto do_arr1; 240   70 case writer::state::arr1: goto do_arr1;
HITCBC 241   2314 case writer::state::arr2: goto do_arr2; 241   2314 case writer::state::arr2: goto do_arr2;
HITCBC 242   40 case writer::state::arr3: goto do_arr3; 242   40 case writer::state::arr3: goto do_arr3;
HITCBC 243   232 case writer::state::arr4: goto do_arr4; 243   232 case writer::state::arr4: goto do_arr4;
244   break; 244   break;
245   } 245   }
246   } 246   }
HITCBC 247   3492 do_arr1: 247   3492 do_arr1:
HITCBC 248   3492 if(BOOST_JSON_LIKELY(ss)) 248   3492 if(BOOST_JSON_LIKELY(ss))
HITCBC 249   3422 ss.append('['); 249   3422 ss.append('[');
250   else 250   else
HITCBC 251   70 return w.suspend(writer::state::arr1, it, pt); 251   70 return w.suspend(writer::state::arr1, it, pt);
HITCBC 252   3422 if(it == end) 252   3422 if(it == end)
HITCBC 253   507 goto do_arr4; 253   507 goto do_arr4;
254   for(;;) 254   for(;;)
255   { 255   {
HITCBC 256   4064 w.p_ = std::addressof(*it); 256   4064 w.p_ = std::addressof(*it);
HITCBC 257   6378 do_arr2: 257   6378 do_arr2:
HITCBC 258   6378 if( !write_impl<Elem, StackEmpty>(w, ss) ) 258   6378 if( !write_impl<Elem, StackEmpty>(w, ss) )
HITCBC 259   2315 return w.suspend(writer::state::arr2, it, pt); 259   2315 return w.suspend(writer::state::arr2, it, pt);
HITCBC 260   4063 if(BOOST_JSON_UNLIKELY( ++it == end )) 260   4063 if(BOOST_JSON_UNLIKELY( ++it == end ))
HITCBC 261   2914 break; 261   2914 break;
HITCBC 262   1149 do_arr3: 262   1149 do_arr3:
HITCBC 263   1189 if(BOOST_JSON_LIKELY(ss)) 263   1189 if(BOOST_JSON_LIKELY(ss))
HITCBC 264   1149 ss.append(','); 264   1149 ss.append(',');
265   else 265   else
HITCBC 266   40 return w.suspend(writer::state::arr3, it, pt); 266   40 return w.suspend(writer::state::arr3, it, pt);
267   } 267   }
HITCBC 268   3653 do_arr4: 268   3653 do_arr4:
HITCBC 269   3653 if(BOOST_JSON_LIKELY(ss)) 269   3653 if(BOOST_JSON_LIKELY(ss))
HITCBC 270   3421 ss.append(']'); 270   3421 ss.append(']');
271   else 271   else
HITCBC 272   232 return w.suspend(writer::state::arr4, it, pt); 272   232 return w.suspend(writer::state::arr4, it, pt);
HITCBC 273   3421 return true; 273   3421 return true;
HITCBC 274   6078 } 274   6078 }
275   275  
276   template<class T, bool StackEmpty> 276   template<class T, bool StackEmpty>
277   BOOST_FORCEINLINE 277   BOOST_FORCEINLINE
278   bool 278   bool
279 - write_impl(map_like_conversion_tag, writer& w, stream& ss0) 279 + write_impl(map_category, writer& w, stream& ss0)
280   { 280   {
281   using It = iterator_type<T const>; 281   using It = iterator_type<T const>;
282   using Mapped = mapped_type<T>; 282   using Mapped = mapped_type<T>;
283   283  
284   T const* pt; 284   T const* pt;
HITCBC 285   27290 local_stream ss(ss0); 285   27290 local_stream ss(ss0);
HITCBC 286   96 It it; 286   96 It it;
HITCBC 287   96 It end; 287   96 It end;
288   #if defined(_MSC_VER) 288   #if defined(_MSC_VER)
289   # pragma warning( push ) 289   # pragma warning( push )
290   # pragma warning( disable : 4127 ) 290   # pragma warning( disable : 4127 )
291   #endif 291   #endif
HITCBC 292   9120 if(StackEmpty || w.st_.empty()) 292   9120 if(StackEmpty || w.st_.empty())
293   #if defined(_MSC_VER) 293   #if defined(_MSC_VER)
294   # pragma warning( pop ) 294   # pragma warning( pop )
295   #endif 295   #endif
296   { 296   {
HITCBC 297   18170 BOOST_ASSERT( w.p_ ); 297   18170 BOOST_ASSERT( w.p_ );
HITCBC 298   18170 pt = reinterpret_cast<T const*>(w.p_); 298   18170 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 299   18170 it = std::begin(*pt); 299   18170 it = std::begin(*pt);
HITCBC 300   36340 end = std::end(*pt); 300   36340 end = std::end(*pt);
301   } 301   }
302   else 302   else
303   { 303   {
304   writer::state st; 304   writer::state st;
HITCBC 305   9120 w.st_.pop(st); 305   9120 w.st_.pop(st);
HITCBC 306   9120 w.st_.pop(it); 306   9120 w.st_.pop(it);
HITCBC 307   9120 w.st_.pop(pt); 307   9120 w.st_.pop(pt);
HITCBC 308   9120 end = std::end(*pt); 308   9120 end = std::end(*pt);
HITCBC 309   9120 switch(st) 309   9120 switch(st)
310   { 310   {
HITCBC 311   12 default: 311   12 default:
HITCBC 312   12 case writer::state::obj1: goto do_obj1; 312   12 case writer::state::obj1: goto do_obj1;
HITCBC 313   296 case writer::state::obj2: goto do_obj2; 313   296 case writer::state::obj2: goto do_obj2;
HITCBC 314   50 case writer::state::obj3: goto do_obj3; 314   50 case writer::state::obj3: goto do_obj3;
HITCBC 315   8700 case writer::state::obj4: goto do_obj4; 315   8700 case writer::state::obj4: goto do_obj4;
HITCBC 316   16 case writer::state::obj5: goto do_obj5; 316   16 case writer::state::obj5: goto do_obj5;
HITCBC 317   46 case writer::state::obj6: goto do_obj6; 317   46 case writer::state::obj6: goto do_obj6;
318   break; 318   break;
319   } 319   }
320   } 320   }
HITCBC 321   18182 do_obj1: 321   18182 do_obj1:
HITCBC 322   18182 if(BOOST_JSON_LIKELY( ss )) 322   18182 if(BOOST_JSON_LIKELY( ss ))
HITCBC 323   18170 ss.append('{'); 323   18170 ss.append('{');
324   else 324   else
HITCBC 325   12 return w.suspend(writer::state::obj1, it, pt); 325   12 return w.suspend(writer::state::obj1, it, pt);
HITCBC 326   18170 if(BOOST_JSON_UNLIKELY( it == end )) 326   18170 if(BOOST_JSON_UNLIKELY( it == end ))
HITCBC 327   563 goto do_obj6; 327   563 goto do_obj6;
HITCBC 328   2129 for(;;) 328   2129 for(;;)
329   { 329   {
330   { 330   {
331   using std::get; 331   using std::get;
HITCBC 332   19736 string_view const sv = get<0>(*it); 332   19736 string_view const sv = get<0>(*it);
HITCBC 333   19736 w.cs0_ = { sv.data(), sv.size() }; 333   19736 w.cs0_ = { sv.data(), sv.size() };
334   } 334   }
335   if( true ) 335   if( true )
336   { 336   {
HITCBC 337   19736 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) )) 337   19736 if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
HITCBC 338   173 return w.suspend(writer::state::obj2, it, pt); 338   173 return w.suspend(writer::state::obj2, it, pt);
339   } 339   }
340   else 340   else
341   { 341   {
HITCBC 342   296 do_obj2: 342   296 do_obj2:
HITCBC 343   296 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) )) 343   296 if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
HITCBC 344   123 return w.suspend(writer::state::obj2, it, pt); 344   123 return w.suspend(writer::state::obj2, it, pt);
345   } 345   }
HITCBC 346   173 do_obj3: 346   173 do_obj3:
HITCBC 347   19786 if(BOOST_JSON_LIKELY(ss)) 347   19786 if(BOOST_JSON_LIKELY(ss))
HITCBC 348   19736 ss.append(':'); 348   19736 ss.append(':');
349   else 349   else
HITCBC 350   50 return w.suspend(writer::state::obj3, it, pt); 350   50 return w.suspend(writer::state::obj3, it, pt);
HITCBC 351   28436 do_obj4: 351   28436 do_obj4:
352   { 352   {
353   using std::get; 353   using std::get;
HITCBC 354   28436 w.p_ = std::addressof( get<1>(*it) ); 354   28436 w.p_ = std::addressof( get<1>(*it) );
355   } 355   }
HITCBC 356   28436 if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) ))) 356   28436 if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
HITCBC 357   8700 return w.suspend(writer::state::obj4, it, pt); 357   8700 return w.suspend(writer::state::obj4, it, pt);
HITCBC 358   19736 ++it; 358   19736 ++it;
HITCBC 359   19736 if(BOOST_JSON_UNLIKELY(it == end)) 359   19736 if(BOOST_JSON_UNLIKELY(it == end))
HITCBC 360   17607 break; 360   17607 break;
HITCBC 361   2129 do_obj5: 361   2129 do_obj5:
HITCBC 362   2145 if(BOOST_JSON_LIKELY(ss)) 362   2145 if(BOOST_JSON_LIKELY(ss))
HITCBC 363   2129 ss.append(','); 363   2129 ss.append(',');
364   else 364   else
HITCBC 365   16 return w.suspend(writer::state::obj5, it, pt); 365   16 return w.suspend(writer::state::obj5, it, pt);
366   } 366   }
HITCBC 367   18216 do_obj6: 367   18216 do_obj6:
HITCBC 368   18216 if(BOOST_JSON_LIKELY( ss )) 368   18216 if(BOOST_JSON_LIKELY( ss ))
369   { 369   {
HITCBC 370   18170 ss.append('}'); 370   18170 ss.append('}');
HITCBC 371   18170 return true; 371   18170 return true;
372   } 372   }
HITCBC 373   46 return w.suspend(writer::state::obj6, it, pt); 373   46 return w.suspend(writer::state::obj6, it, pt);
HITCBC 374   27290 } 374   27290 }
375   375  
376   template< class T, bool StackEmpty > 376   template< class T, bool StackEmpty >
377   struct serialize_tuple_elem_helper 377   struct serialize_tuple_elem_helper
378   { 378   {
379   writer& w; 379   writer& w;
380   stream& ss; 380   stream& ss;
381   T const* pt; 381   T const* pt;
382   382  
383   template< std::size_t I > 383   template< std::size_t I >
384   bool 384   bool
HITCBC 385   258 operator()( std::integral_constant<std::size_t, I> ) const 385   258 operator()( std::integral_constant<std::size_t, I> ) const
386   { 386   {
387   using std::get; 387   using std::get;
HITCBC 388   258 w.p_ = std::addressof( get<I>(*pt) ); 388   258 w.p_ = std::addressof( get<I>(*pt) );
389   389  
390   using Elem = tuple_element_t<I, T>; 390   using Elem = tuple_element_t<I, T>;
HITCBC 391   258 return write_impl<Elem, StackEmpty>(w, ss); 391   258 return write_impl<Elem, StackEmpty>(w, ss);
392   } 392   }
393   }; 393   };
394   394  
395   template<class T, bool StackEmpty> 395   template<class T, bool StackEmpty>
396   BOOST_FORCEINLINE 396   BOOST_FORCEINLINE
397   bool 397   bool
398 - write_impl(tuple_conversion_tag, writer& w, stream& ss0) 398 + write_impl(tuple_category, writer& w, stream& ss0)
399   { 399   {
400   T const* pt; 400   T const* pt;
HITCBC 401   174 local_stream ss(ss0); 401   174 local_stream ss(ss0);
402   std::size_t cur; 402   std::size_t cur;
HITCBC 403   64 constexpr std::size_t N = std::tuple_size<T>::value; 403   64 constexpr std::size_t N = std::tuple_size<T>::value;
404   #if defined(_MSC_VER) 404   #if defined(_MSC_VER)
405   # pragma warning( push ) 405   # pragma warning( push )
406   # pragma warning( disable : 4127 ) 406   # pragma warning( disable : 4127 )
407   #endif 407   #endif
HITCBC 408   110 if(StackEmpty || w.st_.empty()) 408   110 if(StackEmpty || w.st_.empty())
409   { 409   {
410   #if defined(_MSC_VER) 410   #if defined(_MSC_VER)
411   # pragma warning( pop ) 411   # pragma warning( pop )
412   #endif 412   #endif
HITCBC 413   76 BOOST_ASSERT( w.p_ ); 413   76 BOOST_ASSERT( w.p_ );
HITCBC 414   76 pt = reinterpret_cast<T const*>(w.p_); 414   76 pt = reinterpret_cast<T const*>(w.p_);
HITCBC 415   76 cur = 0; 415   76 cur = 0;
416   } 416   }
417   else 417   else
418   { 418   {
419   writer::state st; 419   writer::state st;
HITCBC 420   98 w.st_.pop(st); 420   98 w.st_.pop(st);
HITCBC 421   98 w.st_.pop(cur); 421   98 w.st_.pop(cur);
HITCBC 422   98 w.st_.pop(pt); 422   98 w.st_.pop(pt);
HITCBC 423   98 switch(st) 423   98 switch(st)
424   { 424   {
HITCBC 425   2 default: 425   2 default:
HITCBC 426   2 case writer::state::arr1: goto do_arr1; 426   2 case writer::state::arr1: goto do_arr1;
HITCBC 427   82 case writer::state::arr2: goto do_arr2; 427   82 case writer::state::arr2: goto do_arr2;
HITCBC 428   8 case writer::state::arr3: goto do_arr3; 428   8 case writer::state::arr3: goto do_arr3;
HITCBC 429   6 case writer::state::arr4: goto do_arr4; 429   6 case writer::state::arr4: goto do_arr4;
430   break; 430   break;
431   } 431   }
432   } 432   }
HITCBC 433   78 do_arr1: 433   78 do_arr1:
HITCBC 434   78 if(BOOST_JSON_LIKELY(ss)) 434   78 if(BOOST_JSON_LIKELY(ss))
HITCBC 435   76 ss.append('['); 435   76 ss.append('[');
436   else 436   else
HITCBC 437   2 return w.suspend(writer::state::arr1, cur, pt); 437   2 return w.suspend(writer::state::arr1, cur, pt);
HITCBC 438   100 for(;;) 438   100 for(;;)
439   { 439   {
HITCBC 440   258 do_arr2: 440   258 do_arr2:
441   { 441   {
HITCBC 442   258 bool const stop = !mp11::mp_with_index<N>( 442   258 bool const stop = !mp11::mp_with_index<N>(
443   cur, 443   cur,
444   serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt}); 444   serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
HITCBC 445   258 if(BOOST_JSON_UNLIKELY( stop )) 445   258 if(BOOST_JSON_UNLIKELY( stop ))
HITCBC 446   82 return w.suspend(writer::state::arr2, cur, pt); 446   82 return w.suspend(writer::state::arr2, cur, pt);
447   } 447   }
HITCBC 448   176 if(BOOST_JSON_UNLIKELY( ++cur == N )) 448   176 if(BOOST_JSON_UNLIKELY( ++cur == N ))
HITCBC 449   76 break; 449   76 break;
HITCBC 450   100 do_arr3: 450   100 do_arr3:
HITCBC 451   108 if(BOOST_JSON_LIKELY(ss)) 451   108 if(BOOST_JSON_LIKELY(ss))
HITCBC 452   100 ss.append(','); 452   100 ss.append(',');
453   else 453   else
HITCBC 454   8 return w.suspend(writer::state::arr3, cur, pt); 454   8 return w.suspend(writer::state::arr3, cur, pt);
455   } 455   }
HITCBC 456   82 do_arr4: 456   82 do_arr4:
HITCBC 457   82 if(BOOST_JSON_LIKELY(ss)) 457   82 if(BOOST_JSON_LIKELY(ss))
HITCBC 458   76 ss.append(']'); 458   76 ss.append(']');
459   else 459   else
HITCBC 460   6 return w.suspend(writer::state::arr4, cur, pt); 460   6 return w.suspend(writer::state::arr4, cur, pt);
HITCBC 461   76 return true; 461   76 return true;
HITCBC 462   174 } 462   174 }
463   463  
464   template< class T, bool StackEmpty > 464   template< class T, bool StackEmpty >
465   struct serialize_struct_elem_helper 465   struct serialize_struct_elem_helper
466   { 466   {
467   static_assert( 467   static_assert(
468   uniquely_named_members<T>::value, 468   uniquely_named_members<T>::value,
469   "The type has several described members with the same name."); 469   "The type has several described members with the same name.");
470   470  
471   writer& w; 471   writer& w;
472   local_stream& ss; 472   local_stream& ss;
473   T const* pt; 473   T const* pt;
474   writer::state st; 474   writer::state st;
475   475  
476   template< std::size_t I > 476   template< std::size_t I >
477   writer::state 477   writer::state
478   operator()( std::integral_constant<std::size_t, I> ) const 478   operator()( std::integral_constant<std::size_t, I> ) const
479   { 479   {
480   using Ds = described_members<T>; 480   using Ds = described_members<T>;
481   using D = mp11::mp_at_c<Ds, I>; 481   using D = mp11::mp_at_c<Ds, I>;
482   using M = described_member_t<T, D>; 482   using M = described_member_t<T, D>;
483   483  
484   switch(st) 484   switch(st)
485   { 485   {
486   case writer::state::obj2: goto do_obj2; 486   case writer::state::obj2: goto do_obj2;
487   case writer::state::obj3: goto do_obj3; 487   case writer::state::obj3: goto do_obj3;
488   case writer::state::obj4: goto do_obj4; 488   case writer::state::obj4: goto do_obj4;
489   default: break; 489   default: break;
490   } 490   }
491   491  
492   { 492   {
493   string_view const sv = D::name; 493   string_view const sv = D::name;
494   w.cs0_ = { sv.data(), sv.size() }; 494   w.cs0_ = { sv.data(), sv.size() };
495   } 495   }
496   if( true ) 496   if( true )
497   { 497   {
498   if(BOOST_JSON_UNLIKELY( !write_string(w, ss) )) 498   if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
499   return writer::state::obj2; 499   return writer::state::obj2;
500   } 500   }
501   else 501   else
502   { 502   {
503   do_obj2: 503   do_obj2:
504   if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) )) 504   if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
505   return writer::state::obj2; 505   return writer::state::obj2;
506   } 506   }
507   do_obj3: 507   do_obj3:
508   if(BOOST_JSON_LIKELY(ss)) 508   if(BOOST_JSON_LIKELY(ss))
509   ss.append(':'); 509   ss.append(':');
510   else 510   else
511   return writer::state::obj3; 511   return writer::state::obj3;
512   do_obj4: 512   do_obj4:
513   w.p_ = std::addressof( pt->* D::pointer ); 513   w.p_ = std::addressof( pt->* D::pointer );
514   if(BOOST_JSON_UNLIKELY(( 514   if(BOOST_JSON_UNLIKELY((
515   !write_impl<M, StackEmpty>(w, ss) ))) 515   !write_impl<M, StackEmpty>(w, ss) )))
516   return writer::state::obj4; 516   return writer::state::obj4;
517   517  
518   return writer::state{}; 518   return writer::state{};
519   } 519   }
520   }; 520   };
521   521  
522   template<class T, bool StackEmpty> 522   template<class T, bool StackEmpty>
523   BOOST_FORCEINLINE 523   BOOST_FORCEINLINE
524   bool 524   bool
525 - write_impl(described_class_conversion_tag, writer& w, stream& ss0) 525 + write_impl(described_class_category, writer& w, stream& ss0)
526   { 526   {
527   using Ds = described_members<T>; 527   using Ds = described_members<T>;
528   528  
529   T const* pt; 529   T const* pt;
530   local_stream ss(ss0); 530   local_stream ss(ss0);
531   std::size_t cur; 531   std::size_t cur;
532   constexpr std::size_t N = mp11::mp_size<Ds>::value; 532   constexpr std::size_t N = mp11::mp_size<Ds>::value;
533   writer::state st; 533   writer::state st;
534   #if defined(_MSC_VER) 534   #if defined(_MSC_VER)
535   # pragma warning( push ) 535   # pragma warning( push )
536   # pragma warning( disable : 4127 ) 536   # pragma warning( disable : 4127 )
537   #endif 537   #endif
538   if(StackEmpty || w.st_.empty()) 538   if(StackEmpty || w.st_.empty())
539   #if defined(_MSC_VER) 539   #if defined(_MSC_VER)
540   # pragma warning( pop ) 540   # pragma warning( pop )
541   #endif 541   #endif
542   { 542   {
543   BOOST_ASSERT( w.p_ ); 543   BOOST_ASSERT( w.p_ );
544   pt = reinterpret_cast<T const*>(w.p_); 544   pt = reinterpret_cast<T const*>(w.p_);
545   cur = 0; 545   cur = 0;
546   } 546   }
547   else 547   else
548   { 548   {
549   w.st_.pop(st); 549   w.st_.pop(st);
550   w.st_.pop(cur); 550   w.st_.pop(cur);
551   w.st_.pop(pt); 551   w.st_.pop(pt);
552   switch(st) 552   switch(st)
553   { 553   {
554   default: 554   default:
555   case writer::state::obj1: goto do_obj1; 555   case writer::state::obj1: goto do_obj1;
556   case writer::state::obj2: // fall through 556   case writer::state::obj2: // fall through
557   case writer::state::obj3: // fall through 557   case writer::state::obj3: // fall through
558   case writer::state::obj4: goto do_obj2; 558   case writer::state::obj4: goto do_obj2;
559   case writer::state::obj5: goto do_obj5; 559   case writer::state::obj5: goto do_obj5;
560   case writer::state::obj6: goto do_obj6; 560   case writer::state::obj6: goto do_obj6;
561   break; 561   break;
562   } 562   }
563   } 563   }
564   do_obj1: 564   do_obj1:
565   if(BOOST_JSON_LIKELY( ss )) 565   if(BOOST_JSON_LIKELY( ss ))
566   ss.append('{'); 566   ss.append('{');
567   else 567   else
568   return w.suspend(writer::state::obj1, cur, pt); 568   return w.suspend(writer::state::obj1, cur, pt);
569   if(BOOST_JSON_UNLIKELY( cur == N )) 569   if(BOOST_JSON_UNLIKELY( cur == N ))
570   goto do_obj6; 570   goto do_obj6;
571   for(;;) 571   for(;;)
572   { 572   {
573   st = {}; 573   st = {};
574   do_obj2: 574   do_obj2:
575   st = mp11::mp_with_index<N>( 575   st = mp11::mp_with_index<N>(
576   cur, 576   cur,
577   serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st}); 577   serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
578   if(BOOST_JSON_UNLIKELY( st != writer::state{} )) 578   if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
579   return w.suspend(st, cur, pt); 579   return w.suspend(st, cur, pt);
580   ++cur; 580   ++cur;
581   if(BOOST_JSON_UNLIKELY(cur == N)) 581   if(BOOST_JSON_UNLIKELY(cur == N))
582   break; 582   break;
583   do_obj5: 583   do_obj5:
584   if(BOOST_JSON_LIKELY(ss)) 584   if(BOOST_JSON_LIKELY(ss))
585   ss.append(','); 585   ss.append(',');
586   else 586   else
587   return w.suspend(writer::state::obj5, cur, pt); 587   return w.suspend(writer::state::obj5, cur, pt);
588   } 588   }
589   do_obj6: 589   do_obj6:
590   if(BOOST_JSON_LIKELY( ss )) 590   if(BOOST_JSON_LIKELY( ss ))
591   { 591   {
592   ss.append('}'); 592   ss.append('}');
593   return true; 593   return true;
594   } 594   }
595   return w.suspend(writer::state::obj6, cur, pt); 595   return w.suspend(writer::state::obj6, cur, pt);
596   } 596   }
597   597  
598   template<class T, bool StackEmpty> 598   template<class T, bool StackEmpty>
599   BOOST_FORCEINLINE 599   BOOST_FORCEINLINE
600   bool 600   bool
601 - write_impl(described_enum_conversion_tag, writer& w, stream& ss) 601 + write_impl(described_enum_category, writer& w, stream& ss)
602   { 602   {
603   #ifdef BOOST_DESCRIBE_CXX14 603   #ifdef BOOST_DESCRIBE_CXX14
604   using Integer = typename std::underlying_type<T>::type; 604   using Integer = typename std::underlying_type<T>::type;
605   605  
606   #if defined(_MSC_VER) 606   #if defined(_MSC_VER)
607   # pragma warning( push ) 607   # pragma warning( push )
608   # pragma warning( disable : 4127 ) 608   # pragma warning( disable : 4127 )
609   #endif 609   #endif
610   if(StackEmpty || w.st_.empty()) 610   if(StackEmpty || w.st_.empty())
611   #if defined(_MSC_VER) 611   #if defined(_MSC_VER)
612   # pragma warning( pop ) 612   # pragma warning( pop )
613   #endif 613   #endif
614   { 614   {
615   BOOST_ASSERT( w.p_ ); 615   BOOST_ASSERT( w.p_ );
616   T const* pt = reinterpret_cast<T const*>(w.p_); 616   T const* pt = reinterpret_cast<T const*>(w.p_);
617   char const* const name = describe::enum_to_string(*pt, nullptr); 617   char const* const name = describe::enum_to_string(*pt, nullptr);
618   if( name ) 618   if( name )
619   { 619   {
620   string_view const sv = name; 620   string_view const sv = name;
621   w.cs0_ = { sv.data(), sv.size() }; 621   w.cs0_ = { sv.data(), sv.size() };
622   return write_string(w, ss); 622   return write_string(w, ss);
623   } 623   }
624   else 624   else
625   { 625   {
626   Integer n = static_cast<Integer>(*pt); 626   Integer n = static_cast<Integer>(*pt);
627   w.p_ = &n; 627   w.p_ = &n;
628   return write_impl<Integer, true>(w, ss); 628   return write_impl<Integer, true>(w, ss);
629   } 629   }
630   } 630   }
631   else 631   else
632   { 632   {
633   writer::state st; 633   writer::state st;
634   w.st_.peek(st); 634   w.st_.peek(st);
635   if( st == writer::state::lit ) 635   if( st == writer::state::lit )
636   return write_impl<Integer, false>(w, ss); 636   return write_impl<Integer, false>(w, ss);
637   else 637   else
638   return resume_string(w, ss); 638   return resume_string(w, ss);
639   } 639   }
640   #else // BOOST_DESCRIBE_CXX14 640   #else // BOOST_DESCRIBE_CXX14
641   (void)w; 641   (void)w;
642   (void)ss; 642   (void)ss;
643   static_assert( 643   static_assert(
644   !std::is_same<T, T>::value, 644   !std::is_same<T, T>::value,
645   "described enums require C++14 support"); 645   "described enums require C++14 support");
646   return false; 646   return false;
647   #endif // BOOST_DESCRIBE_CXX14 647   #endif // BOOST_DESCRIBE_CXX14
648   } 648   }
649   649  
650   template< class T, bool StackEmpty > 650   template< class T, bool StackEmpty >
651   struct serialize_variant_elem_helper 651   struct serialize_variant_elem_helper
652   { 652   {
653   writer& w; 653   writer& w;
654   stream& ss; 654   stream& ss;
655   655  
656   template<class Elem> 656   template<class Elem>
657   bool 657   bool
658   operator()(Elem const& x) const 658   operator()(Elem const& x) const
659   { 659   {
660   w.p_ = std::addressof(x); 660   w.p_ = std::addressof(x);
661   return write_impl<Elem, true>(w, ss); 661   return write_impl<Elem, true>(w, ss);
662   } 662   }
663   }; 663   };
664   664  
665   template< class T > 665   template< class T >
666   struct serialize_variant_elem_helper<T, false> 666   struct serialize_variant_elem_helper<T, false>
667   { 667   {
668   writer& w; 668   writer& w;
669   stream& ss; 669   stream& ss;
670   670  
671   template< std::size_t I > 671   template< std::size_t I >
672   bool 672   bool
673   operator()( std::integral_constant<std::size_t, I> ) const 673   operator()( std::integral_constant<std::size_t, I> ) const
674   { 674   {
675   using std::get; 675   using std::get;
676   using Elem = remove_cvref<decltype(get<I>( 676   using Elem = remove_cvref<decltype(get<I>(
677   std::declval<T const&>() ))>; 677   std::declval<T const&>() ))>;
678   return write_impl<Elem, false>(w, ss); 678   return write_impl<Elem, false>(w, ss);
679   } 679   }
680   }; 680   };
681   681  
682   template<class T, bool StackEmpty> 682   template<class T, bool StackEmpty>
683   BOOST_FORCEINLINE 683   BOOST_FORCEINLINE
684   bool 684   bool
685 - write_impl(variant_conversion_tag, writer& w, stream& ss) 685 + write_impl(variant_category, writer& w, stream& ss)
686   { 686   {
687   T const* pt; 687   T const* pt;
688   688  
689   using Index = remove_cvref<decltype( pt->index() )>; 689   using Index = remove_cvref<decltype( pt->index() )>;
690   690  
691   #if defined(_MSC_VER) 691   #if defined(_MSC_VER)
692   # pragma warning( push ) 692   # pragma warning( push )
693   # pragma warning( disable : 4127 ) 693   # pragma warning( disable : 4127 )
694   #endif 694   #endif
695   if(StackEmpty || w.st_.empty()) 695   if(StackEmpty || w.st_.empty())
696   #if defined(_MSC_VER) 696   #if defined(_MSC_VER)
697   # pragma warning( pop ) 697   # pragma warning( pop )
698   #endif 698   #endif
699   { 699   {
700   BOOST_ASSERT( w.p_ ); 700   BOOST_ASSERT( w.p_ );
701   pt = reinterpret_cast<T const*>(w.p_); 701   pt = reinterpret_cast<T const*>(w.p_);
702   if(BOOST_JSON_LIKELY(( 702   if(BOOST_JSON_LIKELY((
703   visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt)))) 703   visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
704   return true; 704   return true;
705   705  
706   Index const ix = pt->index(); 706   Index const ix = pt->index();
707   w.st_.push(ix); 707   w.st_.push(ix);
708   return false; 708   return false;
709   } 709   }
710   else 710   else
711   { 711   {
712   Index ix; 712   Index ix;
713   w.st_.pop(ix); 713   w.st_.pop(ix);
714   714  
715   constexpr std::size_t N = mp11::mp_size<T>::value; 715   constexpr std::size_t N = mp11::mp_size<T>::value;
716   if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>( 716   if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
717   ix, 717   ix,
718   serialize_variant_elem_helper<T, false>{w, ss})))) 718   serialize_variant_elem_helper<T, false>{w, ss}))))
719   return true; 719   return true;
720   720  
721   w.st_.push(ix); 721   w.st_.push(ix);
722   return false; 722   return false;
723   } 723   }
724   } 724   }
725   725  
726   template<class T, bool StackEmpty> 726   template<class T, bool StackEmpty>
727   BOOST_FORCEINLINE 727   BOOST_FORCEINLINE
728   bool 728   bool
729 - write_impl(optional_conversion_tag, writer& w, stream& ss) 729 + write_impl(optional_category, writer& w, stream& ss)
730   { 730   {
731   using Elem = value_result_type<T>; 731   using Elem = value_result_type<T>;
732   732  
733   bool done; 733   bool done;
734   bool has_value; 734   bool has_value;
735   735  
736   #if defined(_MSC_VER) 736   #if defined(_MSC_VER)
737   # pragma warning( push ) 737   # pragma warning( push )
738   # pragma warning( disable : 4127 ) 738   # pragma warning( disable : 4127 )
739   #endif 739   #endif
740   if(StackEmpty || w.st_.empty()) 740   if(StackEmpty || w.st_.empty())
741   #if defined(_MSC_VER) 741   #if defined(_MSC_VER)
742   # pragma warning( pop ) 742   # pragma warning( pop )
743   #endif 743   #endif
744   { 744   {
745   BOOST_ASSERT( w.p_ ); 745   BOOST_ASSERT( w.p_ );
746   T const* pt = reinterpret_cast<T const*>(w.p_); 746   T const* pt = reinterpret_cast<T const*>(w.p_);
747   has_value = static_cast<bool>(*pt); 747   has_value = static_cast<bool>(*pt);
748   if( has_value ) 748   if( has_value )
749   { 749   {
750   w.p_ = std::addressof( *(*pt) ); 750   w.p_ = std::addressof( *(*pt) );
751   done = write_impl<Elem, true>(w, ss); 751   done = write_impl<Elem, true>(w, ss);
752   } 752   }
753   else 753   else
754   { 754   {
755   w.p_ = nullptr; 755   w.p_ = nullptr;
756   done = write_impl<std::nullptr_t, true>(w, ss);; 756   done = write_impl<std::nullptr_t, true>(w, ss);;
757   } 757   }
758   } 758   }
759   else 759   else
760   { 760   {
761   w.st_.pop(has_value); 761   w.st_.pop(has_value);
762   762  
763   if( has_value ) 763   if( has_value )
764   done = write_impl<Elem, false>(w, ss); 764   done = write_impl<Elem, false>(w, ss);
765   else 765   else
766   done = write_impl<std::nullptr_t, false>(w, ss); 766   done = write_impl<std::nullptr_t, false>(w, ss);
767   } 767   }
768   768  
769   if(BOOST_JSON_UNLIKELY( !done )) 769   if(BOOST_JSON_UNLIKELY( !done ))
770   w.st_.push(has_value); 770   w.st_.push(has_value);
771   771  
772   return done; 772   return done;
773   } 773   }
774   774  
775   template<class T, bool StackEmpty> 775   template<class T, bool StackEmpty>
776   BOOST_FORCEINLINE 776   BOOST_FORCEINLINE
777   bool 777   bool
778 - write_impl(path_conversion_tag, writer& w, stream& ss) 778 + write_impl(path_category, writer& w, stream& ss)
779   { 779   {
780   #if defined(_MSC_VER) 780   #if defined(_MSC_VER)
781   # pragma warning( push ) 781   # pragma warning( push )
782   # pragma warning( disable : 4127 ) 782   # pragma warning( disable : 4127 )
783   #endif 783   #endif
784   if(StackEmpty || w.st_.empty()) 784   if(StackEmpty || w.st_.empty())
785   #if defined(_MSC_VER) 785   #if defined(_MSC_VER)
786   # pragma warning( pop ) 786   # pragma warning( pop )
787   #endif 787   #endif
788   { 788   {
789   BOOST_ASSERT( w.p_ ); 789   BOOST_ASSERT( w.p_ );
790   T const* pt = reinterpret_cast<T const*>(w.p_); 790   T const* pt = reinterpret_cast<T const*>(w.p_);
791   791  
792   std::string const s = pt->generic_string(); 792   std::string const s = pt->generic_string();
793   w.cs0_ = { s.data(), s.size() }; 793   w.cs0_ = { s.data(), s.size() };
794   if(BOOST_JSON_LIKELY( write_string(w, ss) )) 794   if(BOOST_JSON_LIKELY( write_string(w, ss) ))
795   return true; 795   return true;
796   796  
797   std::size_t const used = w.cs0_.used( s.data() ); 797   std::size_t const used = w.cs0_.used( s.data() );
798   w.st_.push( used ); 798   w.st_.push( used );
799   w.st_.push( std::move(s) ); 799   w.st_.push( std::move(s) );
800   return false; 800   return false;
801   } 801   }
802   else 802   else
803   { 803   {
804   std::string s; 804   std::string s;
805   std::size_t used; 805   std::size_t used;
806   w.st_.pop( s ); 806   w.st_.pop( s );
807   w.st_.pop( used ); 807   w.st_.pop( used );
808   808  
809   w.cs0_ = { s.data(), s.size() }; 809   w.cs0_ = { s.data(), s.size() };
810   w.cs0_.skip(used); 810   w.cs0_.skip(used);
811   811  
812   if(BOOST_JSON_LIKELY( resume_string(w, ss) )) 812   if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
813   return true; 813   return true;
814   814  
815   used = w.cs0_.used( s.data() ); 815   used = w.cs0_.used( s.data() );
816   w.st_.push( used ); 816   w.st_.push( used );
817   w.st_.push( std::move(s) ); 817   w.st_.push( std::move(s) );
818   return false; 818   return false;
819   } 819   }
820   } 820   }
821   821  
822   template<class T, bool StackEmpty> 822   template<class T, bool StackEmpty>
823   bool 823   bool
HITCBC 824   35604 write_impl(writer& w, stream& ss) 824   35604 write_impl(writer& w, stream& ss)
825   { 825   {
826 - using cat = detail::generic_conversion_category<T>; 826 + using cat = typename conversion_category_of<T>::type;
HITCBC 827   35603 return write_impl<T, StackEmpty>( cat(), w, ss ); 827   35603 return write_impl<T, StackEmpty>( cat(), w, ss );
828   } 828   }
829   829  
830   } // namespace detail 830   } // namespace detail
831   831  
832   template<class T> 832   template<class T>
833   void 833   void
HITCBC 834   219 serializer::reset(T const* p) noexcept 834   219 serializer::reset(T const* p) noexcept
835   { 835   {
836   BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value ); 836   BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
837   BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value ); 837   BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
838   838  
HITCBC 839   219 p_ = p; 839   219 p_ = p;
HITCBC 840   219 fn0_ = &detail::write_impl<T, true>; 840   219 fn0_ = &detail::write_impl<T, true>;
HITCBC 841   219 fn1_ = &detail::write_impl<T, false>; 841   219 fn1_ = &detail::write_impl<T, false>;
HITCBC 842   219 st_.clear(); 842   219 st_.clear();
HITCBC 843   219 done_ = false; 843   219 done_ = false;
HITCBC 844   219 } 844   219 }
845   845  
846   } // namespace json 846   } // namespace json
847   } // namespace boost 847   } // namespace boost
848   848  
849   #endif // BOOST_JSON_IMPL_SERIALIZER_HPP 849   #endif // BOOST_JSON_IMPL_SERIALIZER_HPP