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 -
    static_assert(
 
467 -
        uniquely_named_members<T>::value,
 
468 -
        "The type has several described members with the same name.");
 
469 -

 
470  
{
465  
{
471  
    writer& w;
466  
    writer& w;
472  
    local_stream& ss;
467  
    local_stream& ss;
473  
    T const* pt;
468  
    T const* pt;
474  
    writer::state st;
469  
    writer::state st;
475  

470  

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

478  

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

486  

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

512  

518  
        return writer::state{};
513  
        return writer::state{};
519  
    }
514  
    }
520  
};
515  
};
521  

516  

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

523  

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

592  

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

600  

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

644  

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

650  

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

659  

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

665  

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

676  

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

683  

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

685  

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

700  

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

709  

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

715  

721  
        w.st_.push(ix);
716  
        w.st_.push(ix);
722  
        return false;
717  
        return false;
723  
    }
718  
    }
724  
}
719  
}
725  

720  

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

727  

733  
    bool done;
728  
    bool done;
734  
    bool has_value;
729  
    bool has_value;
735  

730  

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

757  

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

763  

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

766  

772  
    return done;
767  
    return done;
773  
}
768  
}
774  

769  

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

786  

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

791  

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

803  

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

806  

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

809  

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

816  

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

824  

830  
} // namespace detail
825  
} // namespace detail
831  

826  

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

833  

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

840  

846  
} // namespace json
841  
} // namespace json
847  
} // namespace boost
842  
} // namespace boost
848  

843  

849  
#endif // BOOST_JSON_IMPL_SERIALIZER_HPP
844  
#endif // BOOST_JSON_IMPL_SERIALIZER_HPP