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
32  
writer::
32  
writer::
33  
suspend(state st)
33  
suspend(state st)
34  
{
34  
{
35  
    st_.push(st);
35  
    st_.push(st);
36  
    return false;
36  
    return false;
37  
}
37  
}
38  

38  

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

49  

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

53  

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

70  

71  
template<class T, bool StackEmpty>
71  
template<class T, bool StackEmpty>
72  
BOOST_FORCEINLINE
72  
BOOST_FORCEINLINE
73  
bool
73  
bool
74  
write_impl(bool_conversion_tag, writer& w, stream& ss)
74  
write_impl(bool_conversion_tag, writer& w, stream& ss)
75  
{
75  
{
76  
    BOOST_ASSERT( w.p_ );
76  
    BOOST_ASSERT( w.p_ );
77  
    auto const t = *reinterpret_cast<T const*>(w.p_);
77  
    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
83  
    if( StackEmpty || w.st_.empty() )
83  
    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  
    {
88  
        if( t )
88  
        if( t )
89  
            return write_true(w, ss);
89  
            return write_true(w, ss);
90  
        else
90  
        else
91  
            return write_false(w, ss);
91  
            return write_false(w, ss);
92  
    }
92  
    }
93  

93  

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

96  

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

125  
        if( t < 0 )
125  
        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
128  
            if( t >= (std::numeric_limits<std::int64_t>::min)() )
128  
            if( t >= (std::numeric_limits<std::int64_t>::min)() )
129  
            {
129  
            {
130  
                std::int64_t i = t;
130  
                std::int64_t i = t;
131  
                return write_int64(w, ss0, i);
131  
                return write_int64(w, ss0, i);
132  
            }
132  
            }
133  
        }
133  
        }
134  
        else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
134  
        else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
135  
        {
135  
        {
136  
            std::uint64_t u = t;
136  
            std::uint64_t u = t;
137  
            return write_uint64(w, ss0, u);
137  
            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
151  
        double d = t;
151  
        double d = t;
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  

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

160  

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

178  

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

181  

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

200  

201  
    return resume_string(w, ss0);
201  
    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_conversion_tag, 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;
213  
    local_stream ss(ss0);
213  
    local_stream ss(ss0);
214  
    It it;
214  
    It it;
215  
    It end;
215  
    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
220  
    if(StackEmpty || w.st_.empty())
220  
    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
225  
        BOOST_ASSERT( w.p_ );
225  
        BOOST_ASSERT( w.p_ );
226  
        pt = reinterpret_cast<T const*>(w.p_);
226  
        pt = reinterpret_cast<T const*>(w.p_);
227  
        it = std::begin(*pt);
227  
        it = std::begin(*pt);
228  
        end = std::end(*pt);
228  
        end = std::end(*pt);
229  
    }
229  
    }
230  
    else
230  
    else
231  
    {
231  
    {
232  
        writer::state st;
232  
        writer::state st;
233  
        w.st_.pop(st);
233  
        w.st_.pop(st);
234  
        w.st_.pop(it);
234  
        w.st_.pop(it);
235  
        w.st_.pop(pt);
235  
        w.st_.pop(pt);
236  
        end = std::end(*pt);
236  
        end = std::end(*pt);
237  
        switch(st)
237  
        switch(st)
238  
        {
238  
        {
239  
        default:
239  
        default:
240  
        case writer::state::arr1: goto do_arr1;
240  
        case writer::state::arr1: goto do_arr1;
241  
        case writer::state::arr2: goto do_arr2;
241  
        case writer::state::arr2: goto do_arr2;
242  
        case writer::state::arr3: goto do_arr3;
242  
        case writer::state::arr3: goto do_arr3;
243  
        case writer::state::arr4: goto do_arr4;
243  
        case writer::state::arr4: goto do_arr4;
244  
            break;
244  
            break;
245  
        }
245  
        }
246  
    }
246  
    }
247  
do_arr1:
247  
do_arr1:
248  
    if(BOOST_JSON_LIKELY(ss))
248  
    if(BOOST_JSON_LIKELY(ss))
249  
        ss.append('[');
249  
        ss.append('[');
250  
    else
250  
    else
251  
        return w.suspend(writer::state::arr1, it, pt);
251  
        return w.suspend(writer::state::arr1, it, pt);
252  
    if(it == end)
252  
    if(it == end)
253  
        goto do_arr4;
253  
        goto do_arr4;
254  
    for(;;)
254  
    for(;;)
255  
    {
255  
    {
256  
        w.p_ = std::addressof(*it);
256  
        w.p_ = std::addressof(*it);
257  
do_arr2:
257  
do_arr2:
258  
        if( !write_impl<Elem, StackEmpty>(w, ss) )
258  
        if( !write_impl<Elem, StackEmpty>(w, ss) )
259  
            return w.suspend(writer::state::arr2, it, pt);
259  
            return w.suspend(writer::state::arr2, it, pt);
260  
        if(BOOST_JSON_UNLIKELY( ++it == end ))
260  
        if(BOOST_JSON_UNLIKELY( ++it == end ))
261  
            break;
261  
            break;
262  
do_arr3:
262  
do_arr3:
263  
        if(BOOST_JSON_LIKELY(ss))
263  
        if(BOOST_JSON_LIKELY(ss))
264  
            ss.append(',');
264  
            ss.append(',');
265  
        else
265  
        else
266  
            return w.suspend(writer::state::arr3, it, pt);
266  
            return w.suspend(writer::state::arr3, it, pt);
267  
    }
267  
    }
268  
do_arr4:
268  
do_arr4:
269  
    if(BOOST_JSON_LIKELY(ss))
269  
    if(BOOST_JSON_LIKELY(ss))
270  
        ss.append(']');
270  
        ss.append(']');
271  
    else
271  
    else
272  
        return w.suspend(writer::state::arr4, it, pt);
272  
        return w.suspend(writer::state::arr4, it, pt);
273  
    return true;
273  
    return true;
274  
}
274  
}
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_like_conversion_tag, 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;
285  
    local_stream ss(ss0);
285  
    local_stream ss(ss0);
286  
    It it;
286  
    It it;
287  
    It end;
287  
    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
292  
    if(StackEmpty || w.st_.empty())
292  
    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  
    {
297  
        BOOST_ASSERT( w.p_ );
297  
        BOOST_ASSERT( w.p_ );
298  
        pt = reinterpret_cast<T const*>(w.p_);
298  
        pt = reinterpret_cast<T const*>(w.p_);
299  
        it = std::begin(*pt);
299  
        it = std::begin(*pt);
300  
        end = std::end(*pt);
300  
        end = std::end(*pt);
301  
    }
301  
    }
302  
    else
302  
    else
303  
    {
303  
    {
304  
        writer::state st;
304  
        writer::state st;
305  
        w.st_.pop(st);
305  
        w.st_.pop(st);
306  
        w.st_.pop(it);
306  
        w.st_.pop(it);
307  
        w.st_.pop(pt);
307  
        w.st_.pop(pt);
308  
        end = std::end(*pt);
308  
        end = std::end(*pt);
309  
        switch(st)
309  
        switch(st)
310  
        {
310  
        {
311  
        default:
311  
        default:
312  
        case writer::state::obj1: goto do_obj1;
312  
        case writer::state::obj1: goto do_obj1;
313  
        case writer::state::obj2: goto do_obj2;
313  
        case writer::state::obj2: goto do_obj2;
314  
        case writer::state::obj3: goto do_obj3;
314  
        case writer::state::obj3: goto do_obj3;
315  
        case writer::state::obj4: goto do_obj4;
315  
        case writer::state::obj4: goto do_obj4;
316  
        case writer::state::obj5: goto do_obj5;
316  
        case writer::state::obj5: goto do_obj5;
317  
        case writer::state::obj6: goto do_obj6;
317  
        case writer::state::obj6: goto do_obj6;
318  
            break;
318  
            break;
319  
        }
319  
        }
320  
    }
320  
    }
321  
do_obj1:
321  
do_obj1:
322  
    if(BOOST_JSON_LIKELY( ss ))
322  
    if(BOOST_JSON_LIKELY( ss ))
323  
        ss.append('{');
323  
        ss.append('{');
324  
    else
324  
    else
325  
        return w.suspend(writer::state::obj1, it, pt);
325  
        return w.suspend(writer::state::obj1, it, pt);
326  
    if(BOOST_JSON_UNLIKELY( it == end ))
326  
    if(BOOST_JSON_UNLIKELY( it == end ))
327  
        goto do_obj6;
327  
        goto do_obj6;
328  
    for(;;)
328  
    for(;;)
329  
    {
329  
    {
330  
        {
330  
        {
331  
            using std::get;
331  
            using std::get;
332  
            string_view const sv = get<0>(*it);
332  
            string_view const sv = get<0>(*it);
333  
            w.cs0_ = { sv.data(), sv.size() };
333  
            w.cs0_ = { sv.data(), sv.size() };
334  
        }
334  
        }
335  
        if( true )
335  
        if( true )
336  
        {
336  
        {
337  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
337  
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338  
                return w.suspend(writer::state::obj2, it, pt);
338  
                return w.suspend(writer::state::obj2, it, pt);
339  
        }
339  
        }
340  
        else
340  
        else
341  
        {
341  
        {
342  
do_obj2:
342  
do_obj2:
343  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
343  
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344  
                return w.suspend(writer::state::obj2, it, pt);
344  
                return w.suspend(writer::state::obj2, it, pt);
345  
        }
345  
        }
346  
do_obj3:
346  
do_obj3:
347  
        if(BOOST_JSON_LIKELY(ss))
347  
        if(BOOST_JSON_LIKELY(ss))
348  
            ss.append(':');
348  
            ss.append(':');
349  
        else
349  
        else
350  
            return w.suspend(writer::state::obj3, it, pt);
350  
            return w.suspend(writer::state::obj3, it, pt);
351  
do_obj4:
351  
do_obj4:
352  
        {
352  
        {
353  
            using std::get;
353  
            using std::get;
354  
            w.p_ = std::addressof( get<1>(*it) );
354  
            w.p_ = std::addressof( get<1>(*it) );
355  
        }
355  
        }
356  
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
356  
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357  
            return w.suspend(writer::state::obj4, it, pt);
357  
            return w.suspend(writer::state::obj4, it, pt);
358  
        ++it;
358  
        ++it;
359  
        if(BOOST_JSON_UNLIKELY(it == end))
359  
        if(BOOST_JSON_UNLIKELY(it == end))
360  
            break;
360  
            break;
361  
do_obj5:
361  
do_obj5:
362  
        if(BOOST_JSON_LIKELY(ss))
362  
        if(BOOST_JSON_LIKELY(ss))
363  
            ss.append(',');
363  
            ss.append(',');
364  
        else
364  
        else
365  
            return w.suspend(writer::state::obj5, it, pt);
365  
            return w.suspend(writer::state::obj5, it, pt);
366  
    }
366  
    }
367  
do_obj6:
367  
do_obj6:
368  
    if(BOOST_JSON_LIKELY( ss ))
368  
    if(BOOST_JSON_LIKELY( ss ))
369  
    {
369  
    {
370  
        ss.append('}');
370  
        ss.append('}');
371  
        return true;
371  
        return true;
372  
    }
372  
    }
373  
    return w.suspend(writer::state::obj6, it, pt);
373  
    return w.suspend(writer::state::obj6, it, pt);
374  
}
374  
}
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
385  
    operator()( std::integral_constant<std::size_t, I> ) const
385  
    operator()( std::integral_constant<std::size_t, I> ) const
386  
    {
386  
    {
387  
        using std::get;
387  
        using std::get;
388  
        w.p_ = std::addressof( get<I>(*pt) );
388  
        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>;
391  
        return write_impl<Elem, StackEmpty>(w, ss);
391  
        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_conversion_tag, writer& w, stream& ss0)
399  
{
399  
{
400  
    T const* pt;
400  
    T const* pt;
401  
    local_stream ss(ss0);
401  
    local_stream ss(ss0);
402  
    std::size_t cur;
402  
    std::size_t cur;
403  
    constexpr std::size_t N = std::tuple_size<T>::value;
403  
    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
408  
    if(StackEmpty || w.st_.empty())
408  
    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
413  
        BOOST_ASSERT( w.p_ );
413  
        BOOST_ASSERT( w.p_ );
414  
        pt = reinterpret_cast<T const*>(w.p_);
414  
        pt = reinterpret_cast<T const*>(w.p_);
415  
        cur = 0;
415  
        cur = 0;
416  
    }
416  
    }
417  
    else
417  
    else
418  
    {
418  
    {
419  
        writer::state st;
419  
        writer::state st;
420  
        w.st_.pop(st);
420  
        w.st_.pop(st);
421  
        w.st_.pop(cur);
421  
        w.st_.pop(cur);
422  
        w.st_.pop(pt);
422  
        w.st_.pop(pt);
423  
        switch(st)
423  
        switch(st)
424  
        {
424  
        {
425  
        default:
425  
        default:
426  
        case writer::state::arr1: goto do_arr1;
426  
        case writer::state::arr1: goto do_arr1;
427  
        case writer::state::arr2: goto do_arr2;
427  
        case writer::state::arr2: goto do_arr2;
428  
        case writer::state::arr3: goto do_arr3;
428  
        case writer::state::arr3: goto do_arr3;
429  
        case writer::state::arr4: goto do_arr4;
429  
        case writer::state::arr4: goto do_arr4;
430  
            break;
430  
            break;
431  
        }
431  
        }
432  
    }
432  
    }
433  
do_arr1:
433  
do_arr1:
434  
    if(BOOST_JSON_LIKELY(ss))
434  
    if(BOOST_JSON_LIKELY(ss))
435  
        ss.append('[');
435  
        ss.append('[');
436  
    else
436  
    else
437  
        return w.suspend(writer::state::arr1, cur, pt);
437  
        return w.suspend(writer::state::arr1, cur, pt);
438  
    for(;;)
438  
    for(;;)
439  
    {
439  
    {
440  
do_arr2:
440  
do_arr2:
441  
        {
441  
        {
442  
            bool const stop = !mp11::mp_with_index<N>(
442  
            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});
445  
            if(BOOST_JSON_UNLIKELY( stop ))
445  
            if(BOOST_JSON_UNLIKELY( stop ))
446  
                return w.suspend(writer::state::arr2, cur, pt);
446  
                return w.suspend(writer::state::arr2, cur, pt);
447  
        }
447  
        }
448  
        if(BOOST_JSON_UNLIKELY( ++cur == N ))
448  
        if(BOOST_JSON_UNLIKELY( ++cur == N ))
449  
            break;
449  
            break;
450  
do_arr3:
450  
do_arr3:
451  
        if(BOOST_JSON_LIKELY(ss))
451  
        if(BOOST_JSON_LIKELY(ss))
452  
            ss.append(',');
452  
            ss.append(',');
453  
        else
453  
        else
454  
            return w.suspend(writer::state::arr3, cur, pt);
454  
            return w.suspend(writer::state::arr3, cur, pt);
455  
    }
455  
    }
456  
do_arr4:
456  
do_arr4:
457  
    if(BOOST_JSON_LIKELY(ss))
457  
    if(BOOST_JSON_LIKELY(ss))
458  
        ss.append(']');
458  
        ss.append(']');
459  
    else
459  
    else
460  
        return w.suspend(writer::state::arr4, cur, pt);
460  
        return w.suspend(writer::state::arr4, cur, pt);
461  
    return true;
461  
    return true;
462  
}
462  
}
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_conversion_tag, 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_conversion_tag, 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_conversion_tag, 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_conversion_tag, 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_conversion_tag, 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
824  
write_impl(writer& w, stream& ss)
824  
write_impl(writer& w, stream& ss)
825  
{
825  
{
826  
    using cat = detail::generic_conversion_category<T>;
826  
    using cat = detail::generic_conversion_category<T>;
827  
    return write_impl<T, StackEmpty>( cat(), w, ss );
827  
    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
834  
serializer::reset(T const* p) noexcept
834  
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  

839  
    p_ = p;
839  
    p_ = p;
840  
    fn0_ = &detail::write_impl<T, true>;
840  
    fn0_ = &detail::write_impl<T, true>;
841  
    fn1_ = &detail::write_impl<T, false>;
841  
    fn1_ = &detail::write_impl<T, false>;
842  
    st_.clear();
842  
    st_.clear();
843  
    done_ = false;
843  
    done_ = false;
844  
}
844  
}
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