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 -
#include <boost/core/detail/static_assert.hpp>
 
13  

12  

14  
#include <boost/describe/enum_to_string.hpp>
13  
#include <boost/describe/enum_to_string.hpp>
15  
#include <boost/json/conversion.hpp>
14  
#include <boost/json/conversion.hpp>
16  
#include <cstddef>
15  
#include <cstddef>
17  

16  

18  
namespace boost {
17  
namespace boost {
19  
namespace json {
18  
namespace json {
20  
namespace detail {
19  
namespace detail {
21  

20  

22  
enum class writer::state : char
21  
enum class writer::state : char
23  
{
22  
{
24  
    str1, str2, str3, esc1, utf1,
23  
    str1, str2, str3, esc1, utf1,
25  
    utf2, utf3, utf4, utf5,
24  
    utf2, utf3, utf4, utf5,
26  
    lit,
25  
    lit,
27  
    arr1, arr2, arr3, arr4,
26  
    arr1, arr2, arr3, arr4,
28  
    obj1, obj2, obj3, obj4, obj5, obj6
27  
    obj1, obj2, obj3, obj4, obj5, obj6
29  
};
28  
};
30  

29  

31  
bool
30  
bool
32  
writer::
31  
writer::
33  
suspend(state st)
32  
suspend(state st)
34  
{
33  
{
35  
    st_.push(st);
34  
    st_.push(st);
36  
    return false;
35  
    return false;
37  
}
36  
}
38  

37  

39  
template<class U, class T>
38  
template<class U, class T>
40  
bool
39  
bool
41  
writer::
40  
writer::
42  
suspend(state st, U u, T const* pt)
41  
suspend(state st, U u, T const* pt)
43  
{
42  
{
44  
    st_.push(pt);
43  
    st_.push(pt);
45  
    st_.push(u);
44  
    st_.push(u);
46  
    st_.push(st);
45  
    st_.push(st);
47  
    return false;
46  
    return false;
48  
}
47  
}
49  

48  

50  
template<class T, bool StackEmpty>
49  
template<class T, bool StackEmpty>
51  
bool
50  
bool
52  
write_impl(writer& w, stream& ss);
51  
write_impl(writer& w, stream& ss);
53  

52  

54  
template<class T, bool StackEmpty>
53  
template<class T, bool StackEmpty>
55  
BOOST_FORCEINLINE
54  
BOOST_FORCEINLINE
56  
bool
55  
bool
57  
write_impl(null_like_conversion_tag, writer& w, stream& ss)
56  
write_impl(null_like_conversion_tag, writer& w, stream& ss)
58  
{
57  
{
59  
#if defined(_MSC_VER)
58  
#if defined(_MSC_VER)
60  
# pragma warning( push )
59  
# pragma warning( push )
61  
# pragma warning( disable : 4127 )
60  
# pragma warning( disable : 4127 )
62  
#endif
61  
#endif
63  
    if( StackEmpty || w.st_.empty() )
62  
    if( StackEmpty || w.st_.empty() )
64  
        return write_null(w, ss);
63  
        return write_null(w, ss);
65  
#if defined(_MSC_VER)
64  
#if defined(_MSC_VER)
66  
# pragma warning( pop )
65  
# pragma warning( pop )
67  
#endif
66  
#endif
68  
    return resume_buffer(w, ss);
67  
    return resume_buffer(w, ss);
69  
}
68  
}
70  

69  

71  
template<class T, bool StackEmpty>
70  
template<class T, bool StackEmpty>
72  
BOOST_FORCEINLINE
71  
BOOST_FORCEINLINE
73  
bool
72  
bool
74  
write_impl(bool_conversion_tag, writer& w, stream& ss)
73  
write_impl(bool_conversion_tag, writer& w, stream& ss)
75  
{
74  
{
76  
    BOOST_ASSERT( w.p_ );
75  
    BOOST_ASSERT( w.p_ );
77  
    auto const t = *reinterpret_cast<T const*>(w.p_);
76  
    auto const t = *reinterpret_cast<T const*>(w.p_);
78  

77  

79  
#if defined(_MSC_VER)
78  
#if defined(_MSC_VER)
80  
# pragma warning( push )
79  
# pragma warning( push )
81  
# pragma warning( disable : 4127 )
80  
# pragma warning( disable : 4127 )
82  
#endif
81  
#endif
83  
    if( StackEmpty || w.st_.empty() )
82  
    if( StackEmpty || w.st_.empty() )
84  
#if defined(_MSC_VER)
83  
#if defined(_MSC_VER)
85  
# pragma warning( pop )
84  
# pragma warning( pop )
86  
#endif
85  
#endif
87  
    {
86  
    {
88  
        if( t )
87  
        if( t )
89  
            return write_true(w, ss);
88  
            return write_true(w, ss);
90  
        else
89  
        else
91  
            return write_false(w, ss);
90  
            return write_false(w, ss);
92  
    }
91  
    }
93  

92  

94  
    return resume_buffer(w, ss);
93  
    return resume_buffer(w, ss);
95  
}
94  
}
96  

95  

97  
template<class T, bool StackEmpty>
96  
template<class T, bool StackEmpty>
98  
BOOST_FORCEINLINE
97  
BOOST_FORCEINLINE
99  
bool
98  
bool
100  
write_impl(integral_conversion_tag, writer& w, stream& ss0)
99  
write_impl(integral_conversion_tag, writer& w, stream& ss0)
101  
{
100  
{
102  
#if defined(_MSC_VER)
101  
#if defined(_MSC_VER)
103  
# pragma warning( push )
102  
# pragma warning( push )
104  
# pragma warning( disable : 4127 )
103  
# pragma warning( disable : 4127 )
105  
#endif
104  
#endif
106  
    if( StackEmpty || w.st_.empty() )
105  
    if( StackEmpty || w.st_.empty() )
107  
#if defined(_MSC_VER)
106  
#if defined(_MSC_VER)
108  
# pragma warning( pop )
107  
# pragma warning( pop )
109  
#endif
108  
#endif
110  
    {
109  
    {
111  
        auto const& t = *reinterpret_cast<T const*>(w.p_);
110  
        auto const& t = *reinterpret_cast<T const*>(w.p_);
112  

111  

113  
#if defined(__clang__)
112  
#if defined(__clang__)
114  
# pragma clang diagnostic push
113  
# pragma clang diagnostic push
115  
# pragma clang diagnostic ignored "-Wsign-compare"
114  
# pragma clang diagnostic ignored "-Wsign-compare"
116  
#elif defined(__GNUC__)
115  
#elif defined(__GNUC__)
117  
# pragma GCC diagnostic push
116  
# pragma GCC diagnostic push
118  
# pragma GCC  diagnostic ignored "-Wsign-compare"
117  
# pragma GCC  diagnostic ignored "-Wsign-compare"
119  
#elif defined(_MSC_VER)
118  
#elif defined(_MSC_VER)
120  
# pragma warning( push )
119  
# pragma warning( push )
121  
# pragma warning( disable : 4018 )
120  
# pragma warning( disable : 4018 )
122  
# pragma warning( disable : 4127 )
121  
# pragma warning( disable : 4127 )
123  
#endif
122  
#endif
124  

123  

125  
        if( t < 0 )
124  
        if( t < 0 )
126  
        {
125  
        {
127  
            // T is obviously signed, so this comparison is safe
126  
            // T is obviously signed, so this comparison is safe
128  
            if( t >= (std::numeric_limits<std::int64_t>::min)() )
127  
            if( t >= (std::numeric_limits<std::int64_t>::min)() )
129  
            {
128  
            {
130  
                std::int64_t i = t;
129  
                std::int64_t i = t;
131  
                return write_int64(w, ss0, i);
130  
                return write_int64(w, ss0, i);
132  
            }
131  
            }
133  
        }
132  
        }
134  
        else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
133  
        else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
135  
        {
134  
        {
136  
            std::uint64_t u = t;
135  
            std::uint64_t u = t;
137  
            return write_uint64(w, ss0, u);
136  
            return write_uint64(w, ss0, u);
138  
        }
137  
        }
139  
#if defined(__clang__)
138  
#if defined(__clang__)
140  
# pragma clang diagnostic pop
139  
# pragma clang diagnostic pop
141  
#elif defined(__GNUC__)
140  
#elif defined(__GNUC__)
142  
# pragma GCC diagnostic pop
141  
# pragma GCC diagnostic pop
143  
#elif defined(_MSC_VER)
142  
#elif defined(_MSC_VER)
144  
# pragma warning( pop )
143  
# pragma warning( pop )
145  
#endif
144  
#endif
146  

145  

147  
#if defined(_MSC_VER)
146  
#if defined(_MSC_VER)
148  
# pragma warning( push )
147  
# pragma warning( push )
149  
# pragma warning( disable : 4244 )
148  
# pragma warning( disable : 4244 )
150  
#endif
149  
#endif
151  
        double d = t;
150  
        double d = t;
152  
        return write_double(w, ss0, d);
151  
        return write_double(w, ss0, d);
153  
#if defined(_MSC_VER)
152  
#if defined(_MSC_VER)
154  
# pragma warning( pop )
153  
# pragma warning( pop )
155  
#endif
154  
#endif
156  
    }
155  
    }
157  

156  

158  
    return resume_buffer(w, ss0);
157  
    return resume_buffer(w, ss0);
159  
}
158  
}
160  

159  

161  
template<class T, bool StackEmpty>
160  
template<class T, bool StackEmpty>
162  
BOOST_FORCEINLINE
161  
BOOST_FORCEINLINE
163  
bool
162  
bool
164  
write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
163  
write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
165  
{
164  
{
166  
#if defined(_MSC_VER)
165  
#if defined(_MSC_VER)
167  
# pragma warning( push )
166  
# pragma warning( push )
168  
# pragma warning( disable : 4127 )
167  
# pragma warning( disable : 4127 )
169  
#endif
168  
#endif
170  
    if( StackEmpty || w.st_.empty() )
169  
    if( StackEmpty || w.st_.empty() )
171  
#if defined(_MSC_VER)
170  
#if defined(_MSC_VER)
172  
# pragma warning( pop )
171  
# pragma warning( pop )
173  
#endif
172  
#endif
174  
    {
173  
    {
175  
        double d = *reinterpret_cast<T const*>(w.p_);
174  
        double d = *reinterpret_cast<T const*>(w.p_);
176  
        return write_double(w, ss0, d);
175  
        return write_double(w, ss0, d);
177  
    }
176  
    }
178  

177  

179  
    return resume_buffer(w, ss0);
178  
    return resume_buffer(w, ss0);
180  
}
179  
}
181  

180  

182  
template<class T, bool StackEmpty>
181  
template<class T, bool StackEmpty>
183  
BOOST_FORCEINLINE
182  
BOOST_FORCEINLINE
184  
bool
183  
bool
185  
write_impl(string_like_conversion_tag, writer& w, stream& ss0)
184  
write_impl(string_like_conversion_tag, writer& w, stream& ss0)
186  
{
185  
{
187  
#if defined(_MSC_VER)
186  
#if defined(_MSC_VER)
188  
# pragma warning( push )
187  
# pragma warning( push )
189  
# pragma warning( disable : 4127 )
188  
# pragma warning( disable : 4127 )
190  
#endif
189  
#endif
191  
    if( StackEmpty || w.st_.empty() )
190  
    if( StackEmpty || w.st_.empty() )
192  
#if defined(_MSC_VER)
191  
#if defined(_MSC_VER)
193  
# pragma warning( pop )
192  
# pragma warning( pop )
194  
#endif
193  
#endif
195  
    {
194  
    {
196  
        string_view const sv = *reinterpret_cast<T const*>(w.p_);
195  
        string_view const sv = *reinterpret_cast<T const*>(w.p_);
197  
        w.cs0_ = { sv.data(), sv.size() };
196  
        w.cs0_ = { sv.data(), sv.size() };
198  
        return write_string(w, ss0);
197  
        return write_string(w, ss0);
199  
    }
198  
    }
200  

199  

201  
    return resume_string(w, ss0);
200  
    return resume_string(w, ss0);
202  
}
201  
}
203  

202  

204  
template<class T, bool StackEmpty>
203  
template<class T, bool StackEmpty>
205  
BOOST_FORCEINLINE
204  
BOOST_FORCEINLINE
206  
bool
205  
bool
207  
write_impl(sequence_conversion_tag, writer& w, stream& ss0)
206  
write_impl(sequence_conversion_tag, writer& w, stream& ss0)
208  
{
207  
{
209  
    using It = iterator_type<T const>;
208  
    using It = iterator_type<T const>;
210  
    using Elem = value_type<T>;
209  
    using Elem = value_type<T>;
211  

210  

212  
    T const* pt;
211  
    T const* pt;
213  
    local_stream ss(ss0);
212  
    local_stream ss(ss0);
214  
    It it;
213  
    It it;
215  
    It end;
214  
    It end;
216  
#if defined(_MSC_VER)
215  
#if defined(_MSC_VER)
217  
# pragma warning( push )
216  
# pragma warning( push )
218  
# pragma warning( disable : 4127 )
217  
# pragma warning( disable : 4127 )
219  
#endif
218  
#endif
220  
    if(StackEmpty || w.st_.empty())
219  
    if(StackEmpty || w.st_.empty())
221  
    {
220  
    {
222  
#if defined(_MSC_VER)
221  
#if defined(_MSC_VER)
223  
# pragma warning( pop )
222  
# pragma warning( pop )
224  
#endif
223  
#endif
225  
        BOOST_ASSERT( w.p_ );
224  
        BOOST_ASSERT( w.p_ );
226  
        pt = reinterpret_cast<T const*>(w.p_);
225  
        pt = reinterpret_cast<T const*>(w.p_);
227  
        it = std::begin(*pt);
226  
        it = std::begin(*pt);
228  
        end = std::end(*pt);
227  
        end = std::end(*pt);
229  
    }
228  
    }
230  
    else
229  
    else
231  
    {
230  
    {
232  
        writer::state st;
231  
        writer::state st;
233  
        w.st_.pop(st);
232  
        w.st_.pop(st);
234  
        w.st_.pop(it);
233  
        w.st_.pop(it);
235  
        w.st_.pop(pt);
234  
        w.st_.pop(pt);
236  
        end = std::end(*pt);
235  
        end = std::end(*pt);
237  
        switch(st)
236  
        switch(st)
238  
        {
237  
        {
239  
        default:
238  
        default:
240  
        case writer::state::arr1: goto do_arr1;
239  
        case writer::state::arr1: goto do_arr1;
241  
        case writer::state::arr2: goto do_arr2;
240  
        case writer::state::arr2: goto do_arr2;
242  
        case writer::state::arr3: goto do_arr3;
241  
        case writer::state::arr3: goto do_arr3;
243  
        case writer::state::arr4: goto do_arr4;
242  
        case writer::state::arr4: goto do_arr4;
244  
            break;
243  
            break;
245  
        }
244  
        }
246  
    }
245  
    }
247  
do_arr1:
246  
do_arr1:
248  
    if(BOOST_JSON_LIKELY(ss))
247  
    if(BOOST_JSON_LIKELY(ss))
249  
        ss.append('[');
248  
        ss.append('[');
250  
    else
249  
    else
251  
        return w.suspend(writer::state::arr1, it, pt);
250  
        return w.suspend(writer::state::arr1, it, pt);
252  
    if(it == end)
251  
    if(it == end)
253  
        goto do_arr4;
252  
        goto do_arr4;
254  
    for(;;)
253  
    for(;;)
255  
    {
254  
    {
256  
        w.p_ = std::addressof(*it);
255  
        w.p_ = std::addressof(*it);
257  
do_arr2:
256  
do_arr2:
258  
        if( !write_impl<Elem, StackEmpty>(w, ss) )
257  
        if( !write_impl<Elem, StackEmpty>(w, ss) )
259  
            return w.suspend(writer::state::arr2, it, pt);
258  
            return w.suspend(writer::state::arr2, it, pt);
260  
        if(BOOST_JSON_UNLIKELY( ++it == end ))
259  
        if(BOOST_JSON_UNLIKELY( ++it == end ))
261  
            break;
260  
            break;
262  
do_arr3:
261  
do_arr3:
263  
        if(BOOST_JSON_LIKELY(ss))
262  
        if(BOOST_JSON_LIKELY(ss))
264  
            ss.append(',');
263  
            ss.append(',');
265  
        else
264  
        else
266  
            return w.suspend(writer::state::arr3, it, pt);
265  
            return w.suspend(writer::state::arr3, it, pt);
267  
    }
266  
    }
268  
do_arr4:
267  
do_arr4:
269  
    if(BOOST_JSON_LIKELY(ss))
268  
    if(BOOST_JSON_LIKELY(ss))
270  
        ss.append(']');
269  
        ss.append(']');
271  
    else
270  
    else
272  
        return w.suspend(writer::state::arr4, it, pt);
271  
        return w.suspend(writer::state::arr4, it, pt);
273  
    return true;
272  
    return true;
274  
}
273  
}
275  

274  

276  
template<class T, bool StackEmpty>
275  
template<class T, bool StackEmpty>
277  
BOOST_FORCEINLINE
276  
BOOST_FORCEINLINE
278  
bool
277  
bool
279  
write_impl(map_like_conversion_tag, writer& w, stream& ss0)
278  
write_impl(map_like_conversion_tag, writer& w, stream& ss0)
280  
{
279  
{
281  
    using It = iterator_type<T const>;
280  
    using It = iterator_type<T const>;
282  
    using Mapped = mapped_type<T>;
281  
    using Mapped = mapped_type<T>;
283  

282  

284  
    T const* pt;
283  
    T const* pt;
285  
    local_stream ss(ss0);
284  
    local_stream ss(ss0);
286  
    It it;
285  
    It it;
287  
    It end;
286  
    It end;
288  
#if defined(_MSC_VER)
287  
#if defined(_MSC_VER)
289  
# pragma warning( push )
288  
# pragma warning( push )
290  
# pragma warning( disable : 4127 )
289  
# pragma warning( disable : 4127 )
291  
#endif
290  
#endif
292  
    if(StackEmpty || w.st_.empty())
291  
    if(StackEmpty || w.st_.empty())
293  
#if defined(_MSC_VER)
292  
#if defined(_MSC_VER)
294  
# pragma warning( pop )
293  
# pragma warning( pop )
295  
#endif
294  
#endif
296  
    {
295  
    {
297  
        BOOST_ASSERT( w.p_ );
296  
        BOOST_ASSERT( w.p_ );
298  
        pt = reinterpret_cast<T const*>(w.p_);
297  
        pt = reinterpret_cast<T const*>(w.p_);
299  
        it = std::begin(*pt);
298  
        it = std::begin(*pt);
300  
        end = std::end(*pt);
299  
        end = std::end(*pt);
301  
    }
300  
    }
302  
    else
301  
    else
303  
    {
302  
    {
304  
        writer::state st;
303  
        writer::state st;
305  
        w.st_.pop(st);
304  
        w.st_.pop(st);
306  
        w.st_.pop(it);
305  
        w.st_.pop(it);
307  
        w.st_.pop(pt);
306  
        w.st_.pop(pt);
308  
        end = std::end(*pt);
307  
        end = std::end(*pt);
309  
        switch(st)
308  
        switch(st)
310  
        {
309  
        {
311  
        default:
310  
        default:
312  
        case writer::state::obj1: goto do_obj1;
311  
        case writer::state::obj1: goto do_obj1;
313  
        case writer::state::obj2: goto do_obj2;
312  
        case writer::state::obj2: goto do_obj2;
314  
        case writer::state::obj3: goto do_obj3;
313  
        case writer::state::obj3: goto do_obj3;
315  
        case writer::state::obj4: goto do_obj4;
314  
        case writer::state::obj4: goto do_obj4;
316  
        case writer::state::obj5: goto do_obj5;
315  
        case writer::state::obj5: goto do_obj5;
317  
        case writer::state::obj6: goto do_obj6;
316  
        case writer::state::obj6: goto do_obj6;
318  
            break;
317  
            break;
319  
        }
318  
        }
320  
    }
319  
    }
321  
do_obj1:
320  
do_obj1:
322  
    if(BOOST_JSON_LIKELY( ss ))
321  
    if(BOOST_JSON_LIKELY( ss ))
323  
        ss.append('{');
322  
        ss.append('{');
324  
    else
323  
    else
325  
        return w.suspend(writer::state::obj1, it, pt);
324  
        return w.suspend(writer::state::obj1, it, pt);
326  
    if(BOOST_JSON_UNLIKELY( it == end ))
325  
    if(BOOST_JSON_UNLIKELY( it == end ))
327  
        goto do_obj6;
326  
        goto do_obj6;
328  
    for(;;)
327  
    for(;;)
329  
    {
328  
    {
330  
        {
329  
        {
331  
            using std::get;
330  
            using std::get;
332  
            string_view const sv = get<0>(*it);
331  
            string_view const sv = get<0>(*it);
333  
            w.cs0_ = { sv.data(), sv.size() };
332  
            w.cs0_ = { sv.data(), sv.size() };
334  
        }
333  
        }
335  
        if( true )
334  
        if( true )
336  
        {
335  
        {
337  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
336  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338  
                return w.suspend(writer::state::obj2, it, pt);
337  
                return w.suspend(writer::state::obj2, it, pt);
339  
        }
338  
        }
340  
        else
339  
        else
341  
        {
340  
        {
342  
do_obj2:
341  
do_obj2:
343  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
342  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344  
                return w.suspend(writer::state::obj2, it, pt);
343  
                return w.suspend(writer::state::obj2, it, pt);
345  
        }
344  
        }
346  
do_obj3:
345  
do_obj3:
347  
        if(BOOST_JSON_LIKELY(ss))
346  
        if(BOOST_JSON_LIKELY(ss))
348  
            ss.append(':');
347  
            ss.append(':');
349  
        else
348  
        else
350  
            return w.suspend(writer::state::obj3, it, pt);
349  
            return w.suspend(writer::state::obj3, it, pt);
351  
do_obj4:
350  
do_obj4:
352  
        {
351  
        {
353  
            using std::get;
352  
            using std::get;
354  
            w.p_ = std::addressof( get<1>(*it) );
353  
            w.p_ = std::addressof( get<1>(*it) );
355  
        }
354  
        }
356  
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
355  
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357  
            return w.suspend(writer::state::obj4, it, pt);
356  
            return w.suspend(writer::state::obj4, it, pt);
358  
        ++it;
357  
        ++it;
359  
        if(BOOST_JSON_UNLIKELY(it == end))
358  
        if(BOOST_JSON_UNLIKELY(it == end))
360  
            break;
359  
            break;
361  
do_obj5:
360  
do_obj5:
362  
        if(BOOST_JSON_LIKELY(ss))
361  
        if(BOOST_JSON_LIKELY(ss))
363  
            ss.append(',');
362  
            ss.append(',');
364  
        else
363  
        else
365  
            return w.suspend(writer::state::obj5, it, pt);
364  
            return w.suspend(writer::state::obj5, it, pt);
366  
    }
365  
    }
367  
do_obj6:
366  
do_obj6:
368  
    if(BOOST_JSON_LIKELY( ss ))
367  
    if(BOOST_JSON_LIKELY( ss ))
369  
    {
368  
    {
370  
        ss.append('}');
369  
        ss.append('}');
371  
        return true;
370  
        return true;
372  
    }
371  
    }
373  
    return w.suspend(writer::state::obj6, it, pt);
372  
    return w.suspend(writer::state::obj6, it, pt);
374  
}
373  
}
375  

374  

376  
template< class T, bool StackEmpty >
375  
template< class T, bool StackEmpty >
377  
struct serialize_tuple_elem_helper
376  
struct serialize_tuple_elem_helper
378  
{
377  
{
379  
    writer& w;
378  
    writer& w;
380  
    stream& ss;
379  
    stream& ss;
381  
    T const* pt;
380  
    T const* pt;
382  

381  

383  
    template< std::size_t I >
382  
    template< std::size_t I >
384  
    bool
383  
    bool
385  
    operator()( std::integral_constant<std::size_t, I> ) const
384  
    operator()( std::integral_constant<std::size_t, I> ) const
386  
    {
385  
    {
387  
        using std::get;
386  
        using std::get;
388  
        w.p_ = std::addressof( get<I>(*pt) );
387  
        w.p_ = std::addressof( get<I>(*pt) );
389  

388  

390  
        using Elem = tuple_element_t<I, T>;
389  
        using Elem = tuple_element_t<I, T>;
391  
        return write_impl<Elem, StackEmpty>(w, ss);
390  
        return write_impl<Elem, StackEmpty>(w, ss);
392  
    }
391  
    }
393  
};
392  
};
394  

393  

395  
template<class T, bool StackEmpty>
394  
template<class T, bool StackEmpty>
396  
BOOST_FORCEINLINE
395  
BOOST_FORCEINLINE
397  
bool
396  
bool
398  
write_impl(tuple_conversion_tag, writer& w, stream& ss0)
397  
write_impl(tuple_conversion_tag, writer& w, stream& ss0)
399  
{
398  
{
400  
    T const* pt;
399  
    T const* pt;
401  
    local_stream ss(ss0);
400  
    local_stream ss(ss0);
402  
    std::size_t cur;
401  
    std::size_t cur;
403  
    constexpr std::size_t N = std::tuple_size<T>::value;
402  
    constexpr std::size_t N = std::tuple_size<T>::value;
404  
#if defined(_MSC_VER)
403  
#if defined(_MSC_VER)
405  
# pragma warning( push )
404  
# pragma warning( push )
406  
# pragma warning( disable : 4127 )
405  
# pragma warning( disable : 4127 )
407  
#endif
406  
#endif
408  
    if(StackEmpty || w.st_.empty())
407  
    if(StackEmpty || w.st_.empty())
409  
    {
408  
    {
410  
#if defined(_MSC_VER)
409  
#if defined(_MSC_VER)
411  
# pragma warning( pop )
410  
# pragma warning( pop )
412  
#endif
411  
#endif
413  
        BOOST_ASSERT( w.p_ );
412  
        BOOST_ASSERT( w.p_ );
414  
        pt = reinterpret_cast<T const*>(w.p_);
413  
        pt = reinterpret_cast<T const*>(w.p_);
415  
        cur = 0;
414  
        cur = 0;
416  
    }
415  
    }
417  
    else
416  
    else
418  
    {
417  
    {
419  
        writer::state st;
418  
        writer::state st;
420  
        w.st_.pop(st);
419  
        w.st_.pop(st);
421  
        w.st_.pop(cur);
420  
        w.st_.pop(cur);
422  
        w.st_.pop(pt);
421  
        w.st_.pop(pt);
423  
        switch(st)
422  
        switch(st)
424  
        {
423  
        {
425  
        default:
424  
        default:
426  
        case writer::state::arr1: goto do_arr1;
425  
        case writer::state::arr1: goto do_arr1;
427  
        case writer::state::arr2: goto do_arr2;
426  
        case writer::state::arr2: goto do_arr2;
428  
        case writer::state::arr3: goto do_arr3;
427  
        case writer::state::arr3: goto do_arr3;
429  
        case writer::state::arr4: goto do_arr4;
428  
        case writer::state::arr4: goto do_arr4;
430  
            break;
429  
            break;
431  
        }
430  
        }
432  
    }
431  
    }
433  
do_arr1:
432  
do_arr1:
434  
    if(BOOST_JSON_LIKELY(ss))
433  
    if(BOOST_JSON_LIKELY(ss))
435  
        ss.append('[');
434  
        ss.append('[');
436  
    else
435  
    else
437  
        return w.suspend(writer::state::arr1, cur, pt);
436  
        return w.suspend(writer::state::arr1, cur, pt);
438  
    for(;;)
437  
    for(;;)
439  
    {
438  
    {
440  
do_arr2:
439  
do_arr2:
441  
        {
440  
        {
442  
            bool const stop = !mp11::mp_with_index<N>(
441  
            bool const stop = !mp11::mp_with_index<N>(
443  
                cur,
442  
                cur,
444  
                serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
443  
                serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
445  
            if(BOOST_JSON_UNLIKELY( stop ))
444  
            if(BOOST_JSON_UNLIKELY( stop ))
446  
                return w.suspend(writer::state::arr2, cur, pt);
445  
                return w.suspend(writer::state::arr2, cur, pt);
447  
        }
446  
        }
448  
        if(BOOST_JSON_UNLIKELY( ++cur == N ))
447  
        if(BOOST_JSON_UNLIKELY( ++cur == N ))
449  
            break;
448  
            break;
450  
do_arr3:
449  
do_arr3:
451  
        if(BOOST_JSON_LIKELY(ss))
450  
        if(BOOST_JSON_LIKELY(ss))
452  
            ss.append(',');
451  
            ss.append(',');
453  
        else
452  
        else
454  
            return w.suspend(writer::state::arr3, cur, pt);
453  
            return w.suspend(writer::state::arr3, cur, pt);
455  
    }
454  
    }
456  
do_arr4:
455  
do_arr4:
457  
    if(BOOST_JSON_LIKELY(ss))
456  
    if(BOOST_JSON_LIKELY(ss))
458  
        ss.append(']');
457  
        ss.append(']');
459  
    else
458  
    else
460  
        return w.suspend(writer::state::arr4, cur, pt);
459  
        return w.suspend(writer::state::arr4, cur, pt);
461  
    return true;
460  
    return true;
462  
}
461  
}
463  

462  

464  
template< class T, bool StackEmpty >
463  
template< class T, bool StackEmpty >
465  
struct serialize_struct_elem_helper
464  
struct serialize_struct_elem_helper
466  
{
465  
{
467  
    static_assert(
466  
    static_assert(
468  
        uniquely_named_members<T>::value,
467  
        uniquely_named_members<T>::value,
469  
        "The type has several described members with the same name.");
468  
        "The type has several described members with the same name.");
470  

469  

471  
    writer& w;
470  
    writer& w;
472  
    local_stream& ss;
471  
    local_stream& ss;
473  
    T const* pt;
472  
    T const* pt;
474  
    writer::state st;
473  
    writer::state st;
475  

474  

476  
    template< std::size_t I >
475  
    template< std::size_t I >
477  
    writer::state
476  
    writer::state
478  
    operator()( std::integral_constant<std::size_t, I> ) const
477  
    operator()( std::integral_constant<std::size_t, I> ) const
479  
    {
478  
    {
480  
        using Ds = described_members<T>;
479  
        using Ds = described_members<T>;
481  
        using D = mp11::mp_at_c<Ds, I>;
480  
        using D = mp11::mp_at_c<Ds, I>;
482  
        using M = described_member_t<T, D>;
481  
        using M = described_member_t<T, D>;
483  

482  

484  
        switch(st)
483  
        switch(st)
485  
        {
484  
        {
486  
        case writer::state::obj2: goto do_obj2;
485  
        case writer::state::obj2: goto do_obj2;
487  
        case writer::state::obj3: goto do_obj3;
486  
        case writer::state::obj3: goto do_obj3;
488  
        case writer::state::obj4: goto do_obj4;
487  
        case writer::state::obj4: goto do_obj4;
489  
        default: break;
488  
        default: break;
490  
        }
489  
        }
491  

490  

492  
        {
491  
        {
493  
            string_view const sv = D::name;
492  
            string_view const sv = D::name;
494  
            w.cs0_ = { sv.data(), sv.size() };
493  
            w.cs0_ = { sv.data(), sv.size() };
495  
        }
494  
        }
496  
        if( true )
495  
        if( true )
497  
        {
496  
        {
498  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
497  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
499  
                return writer::state::obj2;
498  
                return writer::state::obj2;
500  
        }
499  
        }
501  
        else
500  
        else
502  
        {
501  
        {
503  
do_obj2:
502  
do_obj2:
504  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
503  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
505  
                return writer::state::obj2;
504  
                return writer::state::obj2;
506  
        }
505  
        }
507  
do_obj3:
506  
do_obj3:
508  
        if(BOOST_JSON_LIKELY(ss))
507  
        if(BOOST_JSON_LIKELY(ss))
509  
            ss.append(':');
508  
            ss.append(':');
510  
        else
509  
        else
511  
            return writer::state::obj3;
510  
            return writer::state::obj3;
512  
do_obj4:
511  
do_obj4:
513  
        w.p_ = std::addressof( pt->* D::pointer );
512  
        w.p_ = std::addressof( pt->* D::pointer );
514  
        if(BOOST_JSON_UNLIKELY((
513  
        if(BOOST_JSON_UNLIKELY((
515  
                !write_impl<M, StackEmpty>(w, ss) )))
514  
                !write_impl<M, StackEmpty>(w, ss) )))
516  
            return writer::state::obj4;
515  
            return writer::state::obj4;
517  

516  

518  
        return writer::state{};
517  
        return writer::state{};
519  
    }
518  
    }
520  
};
519  
};
521  

520  

522  
template<class T, bool StackEmpty>
521  
template<class T, bool StackEmpty>
523  
BOOST_FORCEINLINE
522  
BOOST_FORCEINLINE
524  
bool
523  
bool
525  
write_impl(described_class_conversion_tag, writer& w, stream& ss0)
524  
write_impl(described_class_conversion_tag, writer& w, stream& ss0)
526  
{
525  
{
527  
    using Ds = described_members<T>;
526  
    using Ds = described_members<T>;
528  

527  

529  
    T const* pt;
528  
    T const* pt;
530  
    local_stream ss(ss0);
529  
    local_stream ss(ss0);
531  
    std::size_t cur;
530  
    std::size_t cur;
532  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
531  
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
533  
    writer::state st;
532  
    writer::state st;
534  
#if defined(_MSC_VER)
533  
#if defined(_MSC_VER)
535  
# pragma warning( push )
534  
# pragma warning( push )
536  
# pragma warning( disable : 4127 )
535  
# pragma warning( disable : 4127 )
537  
#endif
536  
#endif
538  
    if(StackEmpty || w.st_.empty())
537  
    if(StackEmpty || w.st_.empty())
539  
#if defined(_MSC_VER)
538  
#if defined(_MSC_VER)
540  
# pragma warning( pop )
539  
# pragma warning( pop )
541  
#endif
540  
#endif
542  
    {
541  
    {
543  
        BOOST_ASSERT( w.p_ );
542  
        BOOST_ASSERT( w.p_ );
544  
        pt = reinterpret_cast<T const*>(w.p_);
543  
        pt = reinterpret_cast<T const*>(w.p_);
545  
        cur = 0;
544  
        cur = 0;
546  
    }
545  
    }
547  
    else
546  
    else
548  
    {
547  
    {
549  
        w.st_.pop(st);
548  
        w.st_.pop(st);
550  
        w.st_.pop(cur);
549  
        w.st_.pop(cur);
551  
        w.st_.pop(pt);
550  
        w.st_.pop(pt);
552  
        switch(st)
551  
        switch(st)
553  
        {
552  
        {
554  
        default:
553  
        default:
555  
        case writer::state::obj1: goto do_obj1;
554  
        case writer::state::obj1: goto do_obj1;
556  
        case writer::state::obj2: // fall through
555  
        case writer::state::obj2: // fall through
557  
        case writer::state::obj3: // fall through
556  
        case writer::state::obj3: // fall through
558  
        case writer::state::obj4: goto do_obj2;
557  
        case writer::state::obj4: goto do_obj2;
559  
        case writer::state::obj5: goto do_obj5;
558  
        case writer::state::obj5: goto do_obj5;
560  
        case writer::state::obj6: goto do_obj6;
559  
        case writer::state::obj6: goto do_obj6;
561  
            break;
560  
            break;
562  
        }
561  
        }
563  
    }
562  
    }
564  
do_obj1:
563  
do_obj1:
565  
    if(BOOST_JSON_LIKELY( ss ))
564  
    if(BOOST_JSON_LIKELY( ss ))
566  
        ss.append('{');
565  
        ss.append('{');
567  
    else
566  
    else
568  
        return w.suspend(writer::state::obj1, cur, pt);
567  
        return w.suspend(writer::state::obj1, cur, pt);
569  
    if(BOOST_JSON_UNLIKELY( cur == N ))
568  
    if(BOOST_JSON_UNLIKELY( cur == N ))
570  
        goto do_obj6;
569  
        goto do_obj6;
571  
    for(;;)
570  
    for(;;)
572  
    {
571  
    {
573  
        st = {};
572  
        st = {};
574  
do_obj2:
573  
do_obj2:
575  
        st = mp11::mp_with_index<N>(
574  
        st = mp11::mp_with_index<N>(
576  
            cur,
575  
            cur,
577  
            serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
576  
            serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
578  
        if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
577  
        if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
579  
            return w.suspend(st, cur, pt);
578  
            return w.suspend(st, cur, pt);
580  
        ++cur;
579  
        ++cur;
581  
        if(BOOST_JSON_UNLIKELY(cur == N))
580  
        if(BOOST_JSON_UNLIKELY(cur == N))
582  
            break;
581  
            break;
583  
do_obj5:
582  
do_obj5:
584  
        if(BOOST_JSON_LIKELY(ss))
583  
        if(BOOST_JSON_LIKELY(ss))
585  
            ss.append(',');
584  
            ss.append(',');
586  
        else
585  
        else
587  
            return w.suspend(writer::state::obj5, cur, pt);
586  
            return w.suspend(writer::state::obj5, cur, pt);
588  
    }
587  
    }
589  
do_obj6:
588  
do_obj6:
590  
    if(BOOST_JSON_LIKELY( ss ))
589  
    if(BOOST_JSON_LIKELY( ss ))
591  
    {
590  
    {
592  
        ss.append('}');
591  
        ss.append('}');
593  
        return true;
592  
        return true;
594  
    }
593  
    }
595  
    return w.suspend(writer::state::obj6, cur, pt);
594  
    return w.suspend(writer::state::obj6, cur, pt);
596  
}
595  
}
597  

596  

598  
template<class T, bool StackEmpty>
597  
template<class T, bool StackEmpty>
599  
BOOST_FORCEINLINE
598  
BOOST_FORCEINLINE
600  
bool
599  
bool
601  
write_impl(described_enum_conversion_tag, writer& w, stream& ss)
600  
write_impl(described_enum_conversion_tag, writer& w, stream& ss)
602  
{
601  
{
603  
#ifdef BOOST_DESCRIBE_CXX14
602  
#ifdef BOOST_DESCRIBE_CXX14
604  
    using Integer = typename std::underlying_type<T>::type;
603  
    using Integer = typename std::underlying_type<T>::type;
605  

604  

606  
#if defined(_MSC_VER)
605  
#if defined(_MSC_VER)
607  
# pragma warning( push )
606  
# pragma warning( push )
608  
# pragma warning( disable : 4127 )
607  
# pragma warning( disable : 4127 )
609  
#endif
608  
#endif
610  
    if(StackEmpty || w.st_.empty())
609  
    if(StackEmpty || w.st_.empty())
611  
#if defined(_MSC_VER)
610  
#if defined(_MSC_VER)
612  
# pragma warning( pop )
611  
# pragma warning( pop )
613  
#endif
612  
#endif
614  
    {
613  
    {
615  
        BOOST_ASSERT( w.p_ );
614  
        BOOST_ASSERT( w.p_ );
616  
        T const* pt = reinterpret_cast<T const*>(w.p_);
615  
        T const* pt = reinterpret_cast<T const*>(w.p_);
617  
        char const* const name = describe::enum_to_string(*pt, nullptr);
616  
        char const* const name = describe::enum_to_string(*pt, nullptr);
618  
        if( name )
617  
        if( name )
619  
        {
618  
        {
620  
            string_view const sv = name;
619  
            string_view const sv = name;
621  
            w.cs0_ = { sv.data(), sv.size() };
620  
            w.cs0_ = { sv.data(), sv.size() };
622  
            return write_string(w, ss);
621  
            return write_string(w, ss);
623  
        }
622  
        }
624  
        else
623  
        else
625  
        {
624  
        {
626  
            Integer n = static_cast<Integer>(*pt);
625  
            Integer n = static_cast<Integer>(*pt);
627  
            w.p_ = &n;
626  
            w.p_ = &n;
628  
            return write_impl<Integer, true>(w, ss);
627  
            return write_impl<Integer, true>(w, ss);
629  
        }
628  
        }
630  
    }
629  
    }
631  
    else
630  
    else
632  
    {
631  
    {
633  
        writer::state st;
632  
        writer::state st;
634  
        w.st_.peek(st);
633  
        w.st_.peek(st);
635  
        if( st == writer::state::lit )
634  
        if( st == writer::state::lit )
636  
            return write_impl<Integer, false>(w, ss);
635  
            return write_impl<Integer, false>(w, ss);
637  
        else
636  
        else
638  
            return resume_string(w, ss);
637  
            return resume_string(w, ss);
639  
    }
638  
    }
640  
#else // BOOST_DESCRIBE_CXX14
639  
#else // BOOST_DESCRIBE_CXX14
641  
    (void)w;
640  
    (void)w;
642  
    (void)ss;
641  
    (void)ss;
643  
    static_assert(
642  
    static_assert(
644  
        !std::is_same<T, T>::value,
643  
        !std::is_same<T, T>::value,
645  
        "described enums require C++14 support");
644  
        "described enums require C++14 support");
646  
    return false;
645  
    return false;
647  
#endif // BOOST_DESCRIBE_CXX14
646  
#endif // BOOST_DESCRIBE_CXX14
648  
}
647  
}
649  

648  

650  
template< class T, bool StackEmpty >
649  
template< class T, bool StackEmpty >
651  
struct serialize_variant_elem_helper
650  
struct serialize_variant_elem_helper
652  
{
651  
{
653  
    writer& w;
652  
    writer& w;
654  
    stream& ss;
653  
    stream& ss;
655  

654  

656  
    template<class Elem>
655  
    template<class Elem>
657  
    bool
656  
    bool
658  
    operator()(Elem const& x) const
657  
    operator()(Elem const& x) const
659  
    {
658  
    {
660  
        w.p_ = std::addressof(x);
659  
        w.p_ = std::addressof(x);
661  
        return write_impl<Elem, true>(w, ss);
660  
        return write_impl<Elem, true>(w, ss);
662  
    }
661  
    }
663  
};
662  
};
664  

663  

665  
template< class T >
664  
template< class T >
666  
struct serialize_variant_elem_helper<T, false>
665  
struct serialize_variant_elem_helper<T, false>
667  
{
666  
{
668  
    writer& w;
667  
    writer& w;
669  
    stream& ss;
668  
    stream& ss;
670  

669  

671  
    template< std::size_t I >
670  
    template< std::size_t I >
672  
    bool
671  
    bool
673  
    operator()( std::integral_constant<std::size_t, I> ) const
672  
    operator()( std::integral_constant<std::size_t, I> ) const
674  
    {
673  
    {
675  
        using std::get;
674  
        using std::get;
676  
        using Elem = remove_cvref<decltype(get<I>(
675  
        using Elem = remove_cvref<decltype(get<I>(
677  
            std::declval<T const&>() ))>;
676  
            std::declval<T const&>() ))>;
678  
        return write_impl<Elem, false>(w, ss);
677  
        return write_impl<Elem, false>(w, ss);
679  
    }
678  
    }
680  
};
679  
};
681  

680  

682  
template<class T, bool StackEmpty>
681  
template<class T, bool StackEmpty>
683  
BOOST_FORCEINLINE
682  
BOOST_FORCEINLINE
684  
bool
683  
bool
685  
write_impl(variant_conversion_tag, writer& w, stream& ss)
684  
write_impl(variant_conversion_tag, writer& w, stream& ss)
686  
{
685  
{
687  
    T const* pt;
686  
    T const* pt;
688  

687  

689  
    using Index = remove_cvref<decltype( pt->index() )>;
688  
    using Index = remove_cvref<decltype( pt->index() )>;
690  

689  

691  
#if defined(_MSC_VER)
690  
#if defined(_MSC_VER)
692  
# pragma warning( push )
691  
# pragma warning( push )
693  
# pragma warning( disable : 4127 )
692  
# pragma warning( disable : 4127 )
694  
#endif
693  
#endif
695  
    if(StackEmpty || w.st_.empty())
694  
    if(StackEmpty || w.st_.empty())
696  
#if defined(_MSC_VER)
695  
#if defined(_MSC_VER)
697  
# pragma warning( pop )
696  
# pragma warning( pop )
698  
#endif
697  
#endif
699  
    {
698  
    {
700  
        BOOST_ASSERT( w.p_ );
699  
        BOOST_ASSERT( w.p_ );
701  
        pt = reinterpret_cast<T const*>(w.p_);
700  
        pt = reinterpret_cast<T const*>(w.p_);
702  
        if(BOOST_JSON_LIKELY((
701  
        if(BOOST_JSON_LIKELY((
703  
                visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
702  
                visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
704  
            return true;
703  
            return true;
705  

704  

706  
        Index const ix = pt->index();
705  
        Index const ix = pt->index();
707  
        w.st_.push(ix);
706  
        w.st_.push(ix);
708  
        return false;
707  
        return false;
709  
    }
708  
    }
710  
    else
709  
    else
711  
    {
710  
    {
712  
        Index ix;
711  
        Index ix;
713  
        w.st_.pop(ix);
712  
        w.st_.pop(ix);
714  

713  

715  
        constexpr std::size_t N = mp11::mp_size<T>::value;
714  
        constexpr std::size_t N = mp11::mp_size<T>::value;
716  
        if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
715  
        if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
717  
                ix,
716  
                ix,
718  
                serialize_variant_elem_helper<T, false>{w, ss}))))
717  
                serialize_variant_elem_helper<T, false>{w, ss}))))
719  
            return true;
718  
            return true;
720  

719  

721  
        w.st_.push(ix);
720  
        w.st_.push(ix);
722  
        return false;
721  
        return false;
723  
    }
722  
    }
724  
}
723  
}
725  

724  

726  
template<class T, bool StackEmpty>
725  
template<class T, bool StackEmpty>
727  
BOOST_FORCEINLINE
726  
BOOST_FORCEINLINE
728  
bool
727  
bool
729  
write_impl(optional_conversion_tag, writer& w, stream& ss)
728  
write_impl(optional_conversion_tag, writer& w, stream& ss)
730  
{
729  
{
731  
    using Elem = value_result_type<T>;
730  
    using Elem = value_result_type<T>;
732  

731  

733  
    bool done;
732  
    bool done;
734  
    bool has_value;
733  
    bool has_value;
735  

734  

736  
#if defined(_MSC_VER)
735  
#if defined(_MSC_VER)
737  
# pragma warning( push )
736  
# pragma warning( push )
738  
# pragma warning( disable : 4127 )
737  
# pragma warning( disable : 4127 )
739  
#endif
738  
#endif
740  
    if(StackEmpty || w.st_.empty())
739  
    if(StackEmpty || w.st_.empty())
741  
#if defined(_MSC_VER)
740  
#if defined(_MSC_VER)
742  
# pragma warning( pop )
741  
# pragma warning( pop )
743  
#endif
742  
#endif
744  
    {
743  
    {
745  
        BOOST_ASSERT( w.p_ );
744  
        BOOST_ASSERT( w.p_ );
746  
        T const* pt = reinterpret_cast<T const*>(w.p_);
745  
        T const* pt = reinterpret_cast<T const*>(w.p_);
747  
        has_value = static_cast<bool>(*pt);
746  
        has_value = static_cast<bool>(*pt);
748  
        if( has_value )
747  
        if( has_value )
749  
        {
748  
        {
750  
            w.p_ = std::addressof( *(*pt) );
749  
            w.p_ = std::addressof( *(*pt) );
751  
            done = write_impl<Elem, true>(w, ss);
750  
            done = write_impl<Elem, true>(w, ss);
752  
        }
751  
        }
753  
        else
752  
        else
754  
        {
753  
        {
755  
            w.p_ = nullptr;
754  
            w.p_ = nullptr;
756  
            done = write_impl<std::nullptr_t, true>(w, ss);;
755  
            done = write_impl<std::nullptr_t, true>(w, ss);;
757  
        }
756  
        }
758  
    }
757  
    }
759  
    else
758  
    else
760  
    {
759  
    {
761  
        w.st_.pop(has_value);
760  
        w.st_.pop(has_value);
762  

761  

763  
        if( has_value )
762  
        if( has_value )
764  
            done = write_impl<Elem, false>(w, ss);
763  
            done = write_impl<Elem, false>(w, ss);
765  
        else
764  
        else
766  
            done = write_impl<std::nullptr_t, false>(w, ss);
765  
            done = write_impl<std::nullptr_t, false>(w, ss);
767  
    }
766  
    }
768  

767  

769  
    if(BOOST_JSON_UNLIKELY( !done ))
768  
    if(BOOST_JSON_UNLIKELY( !done ))
770  
        w.st_.push(has_value);
769  
        w.st_.push(has_value);
771  

770  

772  
    return done;
771  
    return done;
773  
}
772  
}
774  

773  

775  
template<class T, bool StackEmpty>
774  
template<class T, bool StackEmpty>
776  
BOOST_FORCEINLINE
775  
BOOST_FORCEINLINE
777  
bool
776  
bool
778  
write_impl(path_conversion_tag, writer& w, stream& ss)
777  
write_impl(path_conversion_tag, writer& w, stream& ss)
779  
{
778  
{
780  
#if defined(_MSC_VER)
779  
#if defined(_MSC_VER)
781  
# pragma warning( push )
780  
# pragma warning( push )
782  
# pragma warning( disable : 4127 )
781  
# pragma warning( disable : 4127 )
783  
#endif
782  
#endif
784  
    if(StackEmpty || w.st_.empty())
783  
    if(StackEmpty || w.st_.empty())
785  
#if defined(_MSC_VER)
784  
#if defined(_MSC_VER)
786  
# pragma warning( pop )
785  
# pragma warning( pop )
787  
#endif
786  
#endif
788  
    {
787  
    {
789  
        BOOST_ASSERT( w.p_ );
788  
        BOOST_ASSERT( w.p_ );
790  
        T const* pt = reinterpret_cast<T const*>(w.p_);
789  
        T const* pt = reinterpret_cast<T const*>(w.p_);
791  

790  

792  
        std::string const s = pt->generic_string();
791  
        std::string const s = pt->generic_string();
793  
        w.cs0_ = { s.data(), s.size() };
792  
        w.cs0_ = { s.data(), s.size() };
794  
        if(BOOST_JSON_LIKELY( write_string(w, ss) ))
793  
        if(BOOST_JSON_LIKELY( write_string(w, ss) ))
795  
            return true;
794  
            return true;
796  

795  

797  
        std::size_t const used = w.cs0_.used( s.data() );
796  
        std::size_t const used = w.cs0_.used( s.data() );
798  
        w.st_.push( used );
797  
        w.st_.push( used );
799  
        w.st_.push( std::move(s) );
798  
        w.st_.push( std::move(s) );
800  
        return false;
799  
        return false;
801  
    }
800  
    }
802  
    else
801  
    else
803  
    {
802  
    {
804  
        std::string s;
803  
        std::string s;
805  
        std::size_t used;
804  
        std::size_t used;
806  
        w.st_.pop( s );
805  
        w.st_.pop( s );
807  
        w.st_.pop( used );
806  
        w.st_.pop( used );
808  

807  

809  
        w.cs0_ = { s.data(), s.size() };
808  
        w.cs0_ = { s.data(), s.size() };
810  
        w.cs0_.skip(used);
809  
        w.cs0_.skip(used);
811  

810  

812  
        if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
811  
        if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
813  
            return true;
812  
            return true;
814  

813  

815  
        used = w.cs0_.used( s.data() );
814  
        used = w.cs0_.used( s.data() );
816  
        w.st_.push( used );
815  
        w.st_.push( used );
817  
        w.st_.push( std::move(s) );
816  
        w.st_.push( std::move(s) );
818  
        return false;
817  
        return false;
819  
    }
818  
    }
820  
}
819  
}
821  

820  

822  
template<class T, bool StackEmpty>
821  
template<class T, bool StackEmpty>
823  
bool
822  
bool
824  
write_impl(writer& w, stream& ss)
823  
write_impl(writer& w, stream& ss)
825  
{
824  
{
826  
    using cat = detail::generic_conversion_category<T>;
825  
    using cat = detail::generic_conversion_category<T>;
827  
    return write_impl<T, StackEmpty>( cat(), w, ss );
826  
    return write_impl<T, StackEmpty>( cat(), w, ss );
828  
}
827  
}
829  

828  

830  
} // namespace detail
829  
} // namespace detail
831  

830  

832  
template<class T>
831  
template<class T>
833  
void
832  
void
834  
serializer::reset(T const* p) noexcept
833  
serializer::reset(T const* p) noexcept
835  
{
834  
{
836 -
    BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
835 +
    BOOST_STATIC_ASSERT( !std::is_pointer<T>::value );
837 -
    BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
836 +
    BOOST_STATIC_ASSERT( std::is_object<T>::value );
838  

837  

839  
    p_ = p;
838  
    p_ = p;
840  
    fn0_ = &detail::write_impl<T, true>;
839  
    fn0_ = &detail::write_impl<T, true>;
841  
    fn1_ = &detail::write_impl<T, false>;
840  
    fn1_ = &detail::write_impl<T, false>;
842  
    st_.clear();
841  
    st_.clear();
843  
    done_ = false;
842  
    done_ = false;
844  
}
843  
}
845  

844  

846  
} // namespace json
845  
} // namespace json
847  
} // namespace boost
846  
} // namespace boost
848  

847  

849  
#endif // BOOST_JSON_IMPL_SERIALIZER_HPP
848  
#endif // BOOST_JSON_IMPL_SERIALIZER_HPP