1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
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_IPP
10  
#ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
11  
#define BOOST_JSON_IMPL_SERIALIZER_IPP
11  
#define BOOST_JSON_IMPL_SERIALIZER_IPP
12  

12  

13  
#include <boost/core/detail/static_assert.hpp>
13  
#include <boost/core/detail/static_assert.hpp>
14  
#include <boost/json/serializer.hpp>
14  
#include <boost/json/serializer.hpp>
15  
#include <boost/json/detail/format.hpp>
15  
#include <boost/json/detail/format.hpp>
16  
#include <boost/json/detail/sse2.hpp>
16  
#include <boost/json/detail/sse2.hpp>
17  

17  

18  
#ifdef _MSC_VER
18  
#ifdef _MSC_VER
19  
#pragma warning(push)
19  
#pragma warning(push)
20  
#pragma warning(disable: 4127) // conditional expression is constant
20  
#pragma warning(disable: 4127) // conditional expression is constant
21  
#endif
21  
#endif
22  

22  

23  
namespace boost {
23  
namespace boost {
24  
namespace json {
24  
namespace json {
25  
namespace detail {
25  
namespace detail {
26  

26  

27  
struct int64_formatter
27  
struct int64_formatter
28  
{
28  
{
29  
    std::int64_t i;
29  
    std::int64_t i;
30  

30  

31  
    std::size_t
31  
    std::size_t
32  
    operator()(char* dst) const noexcept
32  
    operator()(char* dst) const noexcept
33  
    {
33  
    {
34  
        return format_int64(dst, i);
34  
        return format_int64(dst, i);
35  
    }
35  
    }
36  
};
36  
};
37  

37  

38  
struct uint64_formatter
38  
struct uint64_formatter
39  
{
39  
{
40  
    std::uint64_t u;
40  
    std::uint64_t u;
41  

41  

42  
    std::size_t
42  
    std::size_t
43  
    operator()(char* dst) const noexcept
43  
    operator()(char* dst) const noexcept
44  
    {
44  
    {
45  
        return format_uint64(dst, u);
45  
        return format_uint64(dst, u);
46  
    }
46  
    }
47  
};
47  
};
48  

48  

49  
struct double_formatter
49  
struct double_formatter
50  
{
50  
{
51  
    double d;
51  
    double d;
52  
    bool allow_infinity_and_nan;
52  
    bool allow_infinity_and_nan;
53  

53  

54  
    std::size_t
54  
    std::size_t
55  
    operator()(char* dst) const noexcept
55  
    operator()(char* dst) const noexcept
56  
    {
56  
    {
57  
        return format_double(dst, d, allow_infinity_and_nan);
57  
        return format_double(dst, d, allow_infinity_and_nan);
58  
    }
58  
    }
59  
};
59  
};
60  

60  

61  
writer::
61  
writer::
62  
writer(
62  
writer(
63  
    storage_ptr sp,
63  
    storage_ptr sp,
64  
    unsigned char* buf,
64  
    unsigned char* buf,
65  
    std::size_t buf_size,
65  
    std::size_t buf_size,
66  
    serialize_options const& opts) noexcept
66  
    serialize_options const& opts) noexcept
67  
    : st_(
67  
    : st_(
68  
        std::move(sp),
68  
        std::move(sp),
69  
        buf,
69  
        buf,
70  
        buf_size)
70  
        buf_size)
71  
    , opts_(opts)
71  
    , opts_(opts)
72  
{
72  
{
73  
    // ensure room for \uXXXX escape plus one
73  
    // ensure room for \uXXXX escape plus one
74  
    BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
74  
    BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
75  
}
75  
}
76  

76  

77  
bool
77  
bool
78  
BOOST_FORCEINLINE
78  
BOOST_FORCEINLINE
79  
write_buffer(writer& w, stream& ss0)
79  
write_buffer(writer& w, stream& ss0)
80  
{
80  
{
81  
    local_stream ss(ss0);
81  
    local_stream ss(ss0);
82  
    auto const n = ss.remain();
82  
    auto const n = ss.remain();
83  
    if( n < w.cs0_.remain() )
83  
    if( n < w.cs0_.remain() )
84  
    {
84  
    {
85  
        ss.append(w.cs0_.data(), n);
85  
        ss.append(w.cs0_.data(), n);
86  
        w.cs0_.skip(n);
86  
        w.cs0_.skip(n);
87  
        return w.suspend(writer::state::lit);
87  
        return w.suspend(writer::state::lit);
88  
    }
88  
    }
89  
    ss.append( w.cs0_.data(), w.cs0_.remain() );
89  
    ss.append( w.cs0_.data(), w.cs0_.remain() );
90  
    return true;
90  
    return true;
91  
}
91  
}
92  

92  

93  
template< class F >
93  
template< class F >
94  
bool
94  
bool
95  
write_buffer(writer& w, stream& ss0, F f)
95  
write_buffer(writer& w, stream& ss0, F f)
96  
{
96  
{
97  
    BOOST_ASSERT( w.st_.empty() );
97  
    BOOST_ASSERT( w.st_.empty() );
98  

98  

99  
    local_stream ss(ss0);
99  
    local_stream ss(ss0);
100  
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
100  
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101  
    {
101  
    {
102  
        ss.advance( f(ss.data()) );
102  
        ss.advance( f(ss.data()) );
103  
        return true;
103  
        return true;
104  
    }
104  
    }
105  

105  

106  
    w.cs0_ = { w.buf_, f(w.buf_) };
106  
    w.cs0_ = { w.buf_, f(w.buf_) };
107  
    return write_buffer(w, ss);
107  
    return write_buffer(w, ss);
108  
}
108  
}
109  

109  

110  
template<literals Lit>
110  
template<literals Lit>
111  
bool
111  
bool
112  
write_literal(writer& w, stream& ss)
112  
write_literal(writer& w, stream& ss)
113  
{
113  
{
114  
    constexpr std::size_t index = literal_index(Lit);
114  
    constexpr std::size_t index = literal_index(Lit);
115  
    constexpr char const* literal = literal_strings[index];
115  
    constexpr char const* literal = literal_strings[index];
116  
    constexpr std::size_t sz = literal_sizes[index];
116  
    constexpr std::size_t sz = literal_sizes[index];
117  

117  

118  
    std::size_t const n = ss.remain();
118  
    std::size_t const n = ss.remain();
119  
    if(BOOST_JSON_LIKELY( n >= sz ))
119  
    if(BOOST_JSON_LIKELY( n >= sz ))
120  
    {
120  
    {
121  
        ss.append( literal, sz );
121  
        ss.append( literal, sz );
122  
        return true;
122  
        return true;
123  
    }
123  
    }
124  

124  

125  
    ss.append(literal, n);
125  
    ss.append(literal, n);
126  

126  

127  
    w.cs0_ = {literal + n, sz - n};
127  
    w.cs0_ = {literal + n, sz - n};
128  
    return w.suspend(writer::state::lit);
128  
    return w.suspend(writer::state::lit);
129  
}
129  
}
130  

130  

131  
bool
131  
bool
132  
write_true(writer& w, stream& ss)
132  
write_true(writer& w, stream& ss)
133  
{
133  
{
134  
    return write_literal<literals::true_>(w, ss);
134  
    return write_literal<literals::true_>(w, ss);
135  
}
135  
}
136  

136  

137  
bool
137  
bool
138  
write_false(writer& w, stream& ss)
138  
write_false(writer& w, stream& ss)
139  
{
139  
{
140  
    return write_literal<literals::false_>(w, ss);
140  
    return write_literal<literals::false_>(w, ss);
141  
}
141  
}
142  

142  

143  
bool
143  
bool
144  
write_null(writer& w, stream& ss)
144  
write_null(writer& w, stream& ss)
145  
{
145  
{
146  
    return write_literal<literals::null>(w, ss);
146  
    return write_literal<literals::null>(w, ss);
147  
}
147  
}
148  

148  

149  
bool
149  
bool
150  
write_int64(writer& w, stream& ss0, std::int64_t i)
150  
write_int64(writer& w, stream& ss0, std::int64_t i)
151  
{
151  
{
152  
    return write_buffer( w, ss0, int64_formatter{i} );
152  
    return write_buffer( w, ss0, int64_formatter{i} );
153  
}
153  
}
154  

154  

155  
bool
155  
bool
156  
write_uint64(writer& w, stream& ss0, std::uint64_t u)
156  
write_uint64(writer& w, stream& ss0, std::uint64_t u)
157  
{
157  
{
158  
    return write_buffer( w, ss0, uint64_formatter{u} );
158  
    return write_buffer( w, ss0, uint64_formatter{u} );
159  
}
159  
}
160  

160  

161  
bool
161  
bool
162  
write_double(writer& w, stream& ss0, double d)
162  
write_double(writer& w, stream& ss0, double d)
163  
{
163  
{
164  
    return write_buffer(
164  
    return write_buffer(
165  
        w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
165  
        w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
166  
}
166  
}
167  

167  

168  
bool
168  
bool
169  
resume_buffer(writer& w, stream& ss0)
169  
resume_buffer(writer& w, stream& ss0)
170  
{
170  
{
171  
    BOOST_ASSERT( !w.st_.empty() );
171  
    BOOST_ASSERT( !w.st_.empty() );
172  
    writer::state st;
172  
    writer::state st;
173  
    w.st_.pop(st);
173  
    w.st_.pop(st);
174  
    BOOST_ASSERT(st == writer::state::lit);
174  
    BOOST_ASSERT(st == writer::state::lit);
175  

175  

176  
    return write_buffer(w, ss0);
176  
    return write_buffer(w, ss0);
177  
}
177  
}
178  

178  

179  
template<bool StackEmpty>
179  
template<bool StackEmpty>
180  
bool
180  
bool
181  
do_write_string(writer& w, stream& ss0)
181  
do_write_string(writer& w, stream& ss0)
182  
{
182  
{
183  
    local_stream ss(ss0);
183  
    local_stream ss(ss0);
184  
    local_const_stream cs(w.cs0_);
184  
    local_const_stream cs(w.cs0_);
185  
    if(! StackEmpty && ! w.st_.empty())
185  
    if(! StackEmpty && ! w.st_.empty())
186  
    {
186  
    {
187  
        writer::state st;
187  
        writer::state st;
188  
        w.st_.pop(st);
188  
        w.st_.pop(st);
189  
        switch(st)
189  
        switch(st)
190  
        {
190  
        {
191  
        default:
191  
        default:
192  
        case writer::state::str1: goto do_str1;
192  
        case writer::state::str1: goto do_str1;
193  
        case writer::state::str2: goto do_str2;
193  
        case writer::state::str2: goto do_str2;
194  
        case writer::state::str3: goto do_str3;
194  
        case writer::state::str3: goto do_str3;
195  
        case writer::state::esc1: goto do_esc1;
195  
        case writer::state::esc1: goto do_esc1;
196  
        case writer::state::utf1: goto do_utf1;
196  
        case writer::state::utf1: goto do_utf1;
197  
        case writer::state::utf2: goto do_utf2;
197  
        case writer::state::utf2: goto do_utf2;
198  
        case writer::state::utf3: goto do_utf3;
198  
        case writer::state::utf3: goto do_utf3;
199  
        case writer::state::utf4: goto do_utf4;
199  
        case writer::state::utf4: goto do_utf4;
200  
        case writer::state::utf5: goto do_utf5;
200  
        case writer::state::utf5: goto do_utf5;
201  
        }
201  
        }
202  
    }
202  
    }
203  
    static constexpr char hex[] = "0123456789abcdef";
203  
    static constexpr char hex[] = "0123456789abcdef";
204  
    static constexpr char esc[] =
204  
    static constexpr char esc[] =
205  
        "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
205  
        "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
206  
        "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
206  
        "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
207  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
207  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
208  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
208  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
209  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
209  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
210  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
210  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
211  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
211  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
212  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
212  
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
213  

213  

214  
    // opening quote
214  
    // opening quote
215  
do_str1:
215  
do_str1:
216  
    if(BOOST_JSON_LIKELY(ss))
216  
    if(BOOST_JSON_LIKELY(ss))
217  
        ss.append('\x22'); // '"'
217  
        ss.append('\x22'); // '"'
218  
    else
218  
    else
219  
        return w.suspend(writer::state::str1);
219  
        return w.suspend(writer::state::str1);
220  

220  

221  
    // fast loop,
221  
    // fast loop,
222  
    // copy unescaped
222  
    // copy unescaped
223  
do_str2:
223  
do_str2:
224  
    if(BOOST_JSON_LIKELY(ss))
224  
    if(BOOST_JSON_LIKELY(ss))
225  
    {
225  
    {
226  
        std::size_t n = cs.remain();
226  
        std::size_t n = cs.remain();
227  
        if(BOOST_JSON_LIKELY(n > 0))
227  
        if(BOOST_JSON_LIKELY(n > 0))
228  
        {
228  
        {
229  
            if(ss.remain() > n)
229  
            if(ss.remain() > n)
230  
                n = detail::count_unescaped(
230  
                n = detail::count_unescaped(
231  
                    cs.data(), n);
231  
                    cs.data(), n);
232  
            else
232  
            else
233  
                n = detail::count_unescaped(
233  
                n = detail::count_unescaped(
234  
                    cs.data(), ss.remain());
234  
                    cs.data(), ss.remain());
235  
            if(n > 0)
235  
            if(n > 0)
236  
            {
236  
            {
237  
                ss.append(cs.data(), n);
237  
                ss.append(cs.data(), n);
238  
                cs.skip(n);
238  
                cs.skip(n);
239  
                if(! ss)
239  
                if(! ss)
240  
                    return w.suspend(writer::state::str2);
240  
                    return w.suspend(writer::state::str2);
241  
            }
241  
            }
242  
        }
242  
        }
243  
        else
243  
        else
244  
        {
244  
        {
245  
            ss.append('\x22'); // '"'
245  
            ss.append('\x22'); // '"'
246  
            return true;
246  
            return true;
247  
        }
247  
        }
248  
    }
248  
    }
249  
    else
249  
    else
250  
    {
250  
    {
251  
        return w.suspend(writer::state::str2);
251  
        return w.suspend(writer::state::str2);
252  
    }
252  
    }
253  

253  

254  
    // slow loop,
254  
    // slow loop,
255  
    // handle escapes
255  
    // handle escapes
256  
do_str3:
256  
do_str3:
257  
    while(BOOST_JSON_LIKELY(ss))
257  
    while(BOOST_JSON_LIKELY(ss))
258  
    {
258  
    {
259  
        if(BOOST_JSON_LIKELY(cs))
259  
        if(BOOST_JSON_LIKELY(cs))
260  
        {
260  
        {
261  
            auto const ch = *cs;
261  
            auto const ch = *cs;
262  
            auto const c = esc[static_cast<
262  
            auto const c = esc[static_cast<
263  
                unsigned char>(ch)];
263  
                unsigned char>(ch)];
264  
            ++cs;
264  
            ++cs;
265  
            if(! c)
265  
            if(! c)
266  
            {
266  
            {
267  
                ss.append(ch);
267  
                ss.append(ch);
268  
            }
268  
            }
269  
            else if(c != 'u')
269  
            else if(c != 'u')
270  
            {
270  
            {
271  
                ss.append('\\');
271  
                ss.append('\\');
272  
                if(BOOST_JSON_LIKELY(ss))
272  
                if(BOOST_JSON_LIKELY(ss))
273  
                {
273  
                {
274  
                    ss.append(c);
274  
                    ss.append(c);
275  
                }
275  
                }
276  
                else
276  
                else
277  
                {
277  
                {
278  
                    w.buf_[0] = c;
278  
                    w.buf_[0] = c;
279  
                    return w.suspend(
279  
                    return w.suspend(
280  
                        writer::state::esc1);
280  
                        writer::state::esc1);
281  
                }
281  
                }
282  
            }
282  
            }
283  
            else
283  
            else
284  
            {
284  
            {
285  
                if(BOOST_JSON_LIKELY(
285  
                if(BOOST_JSON_LIKELY(
286  
                    ss.remain() >= 6))
286  
                    ss.remain() >= 6))
287  
                {
287  
                {
288  
                    ss.append("\\u00", 4);
288  
                    ss.append("\\u00", 4);
289  
                    ss.append(hex[static_cast<
289  
                    ss.append(hex[static_cast<
290  
                        unsigned char>(ch) >> 4]);
290  
                        unsigned char>(ch) >> 4]);
291  
                    ss.append(hex[static_cast<
291  
                    ss.append(hex[static_cast<
292  
                        unsigned char>(ch) & 15]);
292  
                        unsigned char>(ch) & 15]);
293  
                }
293  
                }
294  
                else
294  
                else
295  
                {
295  
                {
296  
                    ss.append('\\');
296  
                    ss.append('\\');
297  
                    w.buf_[0] = hex[static_cast<
297  
                    w.buf_[0] = hex[static_cast<
298  
                        unsigned char>(ch) >> 4];
298  
                        unsigned char>(ch) >> 4];
299  
                    w.buf_[1] = hex[static_cast<
299  
                    w.buf_[1] = hex[static_cast<
300  
                        unsigned char>(ch) & 15];
300  
                        unsigned char>(ch) & 15];
301  
                    goto do_utf1;
301  
                    goto do_utf1;
302  
                }
302  
                }
303  
            }
303  
            }
304  
        }
304  
        }
305  
        else
305  
        else
306  
        {
306  
        {
307  
            ss.append('\x22'); // '"'
307  
            ss.append('\x22'); // '"'
308  
            return true;
308  
            return true;
309  
        }
309  
        }
310  
    }
310  
    }
311  
    return w.suspend(writer::state::str3);
311  
    return w.suspend(writer::state::str3);
312  

312  

313  
do_esc1:
313  
do_esc1:
314  
    BOOST_ASSERT(ss);
314  
    BOOST_ASSERT(ss);
315  
    ss.append(w.buf_[0]);
315  
    ss.append(w.buf_[0]);
316  
    goto do_str3;
316  
    goto do_str3;
317  

317  

318  
do_utf1:
318  
do_utf1:
319  
    if(BOOST_JSON_LIKELY(ss))
319  
    if(BOOST_JSON_LIKELY(ss))
320  
        ss.append('u');
320  
        ss.append('u');
321  
    else
321  
    else
322  
        return w.suspend(writer::state::utf1);
322  
        return w.suspend(writer::state::utf1);
323  
do_utf2:
323  
do_utf2:
324  
    if(BOOST_JSON_LIKELY(ss))
324  
    if(BOOST_JSON_LIKELY(ss))
325  
        ss.append('0');
325  
        ss.append('0');
326  
    else
326  
    else
327  
        return w.suspend(writer::state::utf2);
327  
        return w.suspend(writer::state::utf2);
328  
do_utf3:
328  
do_utf3:
329  
    if(BOOST_JSON_LIKELY(ss))
329  
    if(BOOST_JSON_LIKELY(ss))
330  
        ss.append('0');
330  
        ss.append('0');
331  
    else
331  
    else
332  
        return w.suspend(writer::state::utf3);
332  
        return w.suspend(writer::state::utf3);
333  
do_utf4:
333  
do_utf4:
334  
    if(BOOST_JSON_LIKELY(ss))
334  
    if(BOOST_JSON_LIKELY(ss))
335  
        ss.append(w.buf_[0]);
335  
        ss.append(w.buf_[0]);
336  
    else
336  
    else
337  
        return w.suspend(writer::state::utf4);
337  
        return w.suspend(writer::state::utf4);
338  
do_utf5:
338  
do_utf5:
339  
    if(BOOST_JSON_LIKELY(ss))
339  
    if(BOOST_JSON_LIKELY(ss))
340  
        ss.append(w.buf_[1]);
340  
        ss.append(w.buf_[1]);
341  
    else
341  
    else
342  
        return w.suspend(writer::state::utf5);
342  
        return w.suspend(writer::state::utf5);
343  
    goto do_str3;
343  
    goto do_str3;
344  
}
344  
}
345  

345  

346  
bool
346  
bool
347  
write_string(writer& w, stream& ss0)
347  
write_string(writer& w, stream& ss0)
348  
{
348  
{
349  
    return do_write_string<true>(w, ss0);
349  
    return do_write_string<true>(w, ss0);
350  
}
350  
}
351  

351  

352  
bool
352  
bool
353  
resume_string(writer& w, stream& ss0)
353  
resume_string(writer& w, stream& ss0)
354  
{
354  
{
355  
    return do_write_string<false>(w, ss0);
355  
    return do_write_string<false>(w, ss0);
356  
}
356  
}
357  

357  

358  
template<bool StackEmpty>
358  
template<bool StackEmpty>
359  
bool
359  
bool
360  
write_value(writer& w, stream& ss);
360  
write_value(writer& w, stream& ss);
361  

361  

362  
template< class T, bool StackEmpty >
362  
template< class T, bool StackEmpty >
363  
BOOST_FORCEINLINE
363  
BOOST_FORCEINLINE
364  
bool
364  
bool
365  
write_impl(no_conversion_tag, writer& w, stream& ss)
365  
write_impl(no_conversion_tag, writer& w, stream& ss)
366  
{
366  
{
367  
    return write_value<StackEmpty>(w, ss);
367  
    return write_value<StackEmpty>(w, ss);
368  
}
368  
}
369  

369  

370  
template<bool StackEmpty>
370  
template<bool StackEmpty>
371  
bool
371  
bool
372  
write_array(writer& w, stream& ss)
372  
write_array(writer& w, stream& ss)
373  
{
373  
{
374  
    return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
374  
    return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375  
}
375  
}
376  

376  

377  
template<bool StackEmpty>
377  
template<bool StackEmpty>
378  
bool
378  
bool
379  
write_object(writer& w, stream& ss)
379  
write_object(writer& w, stream& ss)
380  
{
380  
{
381  
    return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
381  
    return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382  
}
382  
}
383  

383  

384  
template<bool StackEmpty>
384  
template<bool StackEmpty>
385  
bool
385  
bool
386  
write_value(writer& w, stream& ss)
386  
write_value(writer& w, stream& ss)
387  
{
387  
{
388  
    if(StackEmpty || w.st_.empty())
388  
    if(StackEmpty || w.st_.empty())
389  
    {
389  
    {
390  
        BOOST_ASSERT( w.p_ );
390  
        BOOST_ASSERT( w.p_ );
391  
        auto const pv = reinterpret_cast<value const*>(w.p_);
391  
        auto const pv = reinterpret_cast<value const*>(w.p_);
392  
        switch(pv->kind())
392  
        switch(pv->kind())
393  
        {
393  
        {
394  
        default:
394  
        default:
395  
        case kind::object:
395  
        case kind::object:
396  
            w.p_ = &pv->get_object();
396  
            w.p_ = &pv->get_object();
397  
            return write_object<true>(w, ss);
397  
            return write_object<true>(w, ss);
398  

398  

399  
        case kind::array:
399  
        case kind::array:
400  
            w.p_ = &pv->get_array();
400  
            w.p_ = &pv->get_array();
401  
            return write_array<true>(w, ss);
401  
            return write_array<true>(w, ss);
402  

402  

403  
        case kind::string:
403  
        case kind::string:
404  
        {
404  
        {
405  
            auto const& js = pv->get_string();
405  
            auto const& js = pv->get_string();
406  
            w.cs0_ = { js.data(), js.size() };
406  
            w.cs0_ = { js.data(), js.size() };
407  
            return do_write_string<true>(w, ss);
407  
            return do_write_string<true>(w, ss);
408  
        }
408  
        }
409  

409  

410  
        case kind::int64:
410  
        case kind::int64:
411  
            return write_int64( w, ss, pv->get_int64() );
411  
            return write_int64( w, ss, pv->get_int64() );
412  
        case kind::uint64:
412  
        case kind::uint64:
413  
            return write_uint64( w, ss, pv->get_uint64() );
413  
            return write_uint64( w, ss, pv->get_uint64() );
414  
        case kind::double_:
414  
        case kind::double_:
415  
            return write_double( w, ss, pv->get_double() );
415  
            return write_double( w, ss, pv->get_double() );
416  

416  

417  
        case kind::bool_:
417  
        case kind::bool_:
418  
            if( pv->get_bool() )
418  
            if( pv->get_bool() )
419  
                return write_true(w, ss);
419  
                return write_true(w, ss);
420  
            else
420  
            else
421  
                return write_false(w, ss);
421  
                return write_false(w, ss);
422  

422  

423  
        case kind::null:
423  
        case kind::null:
424  
            return write_null(w, ss);
424  
            return write_null(w, ss);
425  
        }
425  
        }
426  
    }
426  
    }
427  
    else
427  
    else
428  
    {
428  
    {
429  
        writer::state st;
429  
        writer::state st;
430  
        w.st_.peek(st);
430  
        w.st_.peek(st);
431  
        switch(st)
431  
        switch(st)
432  
        {
432  
        {
433  
        default:
433  
        default:
434  
        case writer::state::lit:
434  
        case writer::state::lit:
435  
            return resume_buffer(w, ss);
435  
            return resume_buffer(w, ss);
436  

436  

437  
        case writer::state::str1: case writer::state::str2:
437  
        case writer::state::str1: case writer::state::str2:
438  
        case writer::state::str3: case writer::state::esc1:
438  
        case writer::state::str3: case writer::state::esc1:
439  
        case writer::state::utf1: case writer::state::utf2:
439  
        case writer::state::utf1: case writer::state::utf2:
440  
        case writer::state::utf3: case writer::state::utf4:
440  
        case writer::state::utf3: case writer::state::utf4:
441  
        case writer::state::utf5:
441  
        case writer::state::utf5:
442  
            return do_write_string<false>(w, ss);
442  
            return do_write_string<false>(w, ss);
443  

443  

444  
        case writer::state::arr1: case writer::state::arr2:
444  
        case writer::state::arr1: case writer::state::arr2:
445  
        case writer::state::arr3: case writer::state::arr4:
445  
        case writer::state::arr3: case writer::state::arr4:
446  
            return write_array<StackEmpty>(w, ss);
446  
            return write_array<StackEmpty>(w, ss);
447  

447  

448  
        case writer::state::obj1: case writer::state::obj2:
448  
        case writer::state::obj1: case writer::state::obj2:
449  
        case writer::state::obj3: case writer::state::obj4:
449  
        case writer::state::obj3: case writer::state::obj4:
450  
        case writer::state::obj5: case writer::state::obj6:
450  
        case writer::state::obj5: case writer::state::obj6:
451  
            return write_object<StackEmpty>(w, ss);
451  
            return write_object<StackEmpty>(w, ss);
452  
        }
452  
        }
453  
    }
453  
    }
454  
}
454  
}
455  

455  

456  
} // namespace detail
456  
} // namespace detail
457  

457  

458  
serializer::
458  
serializer::
459  
serializer(serialize_options const& opts) noexcept
459  
serializer(serialize_options const& opts) noexcept
460  
    : serializer({}, nullptr, 0, opts)
460  
    : serializer({}, nullptr, 0, opts)
461  
{}
461  
{}
462  

462  

463  
serializer::
463  
serializer::
464  
serializer(
464  
serializer(
465  
    storage_ptr sp,
465  
    storage_ptr sp,
466  
    unsigned char* buf,
466  
    unsigned char* buf,
467  
    std::size_t buf_size,
467  
    std::size_t buf_size,
468  
    serialize_options const& opts) noexcept
468  
    serialize_options const& opts) noexcept
469  
    : detail::writer(std::move(sp), buf, buf_size, opts)
469  
    : detail::writer(std::move(sp), buf, buf_size, opts)
470  
{}
470  
{}
471  

471  

472  
void
472  
void
473  
serializer::
473  
serializer::
474  
reset(value const* p) noexcept
474  
reset(value const* p) noexcept
475  
{
475  
{
476  
    p_ = p;
476  
    p_ = p;
477  
    fn0_ = &detail::write_value<true>;
477  
    fn0_ = &detail::write_value<true>;
478  
    fn1_ = &detail::write_value<false>;
478  
    fn1_ = &detail::write_value<false>;
479  
    st_.clear();
479  
    st_.clear();
480  
    done_ = false;
480  
    done_ = false;
481  
}
481  
}
482  

482  

483  
void
483  
void
484  
serializer::
484  
serializer::
485  
reset(array const* p) noexcept
485  
reset(array const* p) noexcept
486  
{
486  
{
487  
    p_ = p;
487  
    p_ = p;
488  
    fn0_ = &detail::write_array<true>;
488  
    fn0_ = &detail::write_array<true>;
489  
    fn1_ = &detail::write_array<false>;
489  
    fn1_ = &detail::write_array<false>;
490  
    st_.clear();
490  
    st_.clear();
491  
    done_ = false;
491  
    done_ = false;
492  
}
492  
}
493  

493  

494  
void
494  
void
495  
serializer::
495  
serializer::
496  
reset(object const* p) noexcept
496  
reset(object const* p) noexcept
497  
{
497  
{
498  
    p_ = p;
498  
    p_ = p;
499  
    fn0_ = &detail::write_object<true>;
499  
    fn0_ = &detail::write_object<true>;
500  
    fn1_ = &detail::write_object<false>;
500  
    fn1_ = &detail::write_object<false>;
501  
    st_.clear();
501  
    st_.clear();
502  
    done_ = false;
502  
    done_ = false;
503  
}
503  
}
504  

504  

505  
void
505  
void
506  
serializer::
506  
serializer::
507  
reset(string const* p) noexcept
507  
reset(string const* p) noexcept
508  
{
508  
{
509  
    cs0_ = { p->data(), p->size() };
509  
    cs0_ = { p->data(), p->size() };
510  
    fn0_ = &detail::do_write_string<true>;
510  
    fn0_ = &detail::do_write_string<true>;
511  
    fn1_ = &detail::do_write_string<false>;
511  
    fn1_ = &detail::do_write_string<false>;
512  
    st_.clear();
512  
    st_.clear();
513  
    done_ = false;
513  
    done_ = false;
514  
}
514  
}
515  

515  

516  
void
516  
void
517  
serializer::
517  
serializer::
518  
reset(string_view sv) noexcept
518  
reset(string_view sv) noexcept
519  
{
519  
{
520  
    cs0_ = { sv.data(), sv.size() };
520  
    cs0_ = { sv.data(), sv.size() };
521  
    fn0_ = &detail::do_write_string<true>;
521  
    fn0_ = &detail::do_write_string<true>;
522  
    fn1_ = &detail::do_write_string<false>;
522  
    fn1_ = &detail::do_write_string<false>;
523  
    st_.clear();
523  
    st_.clear();
524  
    done_ = false;
524  
    done_ = false;
525  
}
525  
}
526  

526  

527  
void
527  
void
528  
serializer::reset(std::nullptr_t) noexcept
528  
serializer::reset(std::nullptr_t) noexcept
529  
{
529  
{
530  
    p_ = nullptr;
530  
    p_ = nullptr;
531  
    fn0_ = &detail::write_impl<std::nullptr_t, true>;
531  
    fn0_ = &detail::write_impl<std::nullptr_t, true>;
532  
    fn1_ = &detail::write_impl<std::nullptr_t, false>;
532  
    fn1_ = &detail::write_impl<std::nullptr_t, false>;
533  
    st_.clear();
533  
    st_.clear();
534  
    done_ = false;
534  
    done_ = false;
535  
}
535  
}
536  

536  

537  
string_view
537  
string_view
538  
serializer::
538  
serializer::
539  
read(char* dest, std::size_t size)
539  
read(char* dest, std::size_t size)
540  
{
540  
{
541  
    if( !fn0_ )
541  
    if( !fn0_ )
542  
        reset(nullptr);
542  
        reset(nullptr);
543  

543  

544  
    if(BOOST_JSON_UNLIKELY(size == 0))
544  
    if(BOOST_JSON_UNLIKELY(size == 0))
545  
        return {dest, 0};
545  
        return {dest, 0};
546  

546  

547  
    detail::stream ss(dest, size);
547  
    detail::stream ss(dest, size);
548  
    if(st_.empty())
548  
    if(st_.empty())
549  
        fn0_(*this, ss);
549  
        fn0_(*this, ss);
550  
    else
550  
    else
551  
        fn1_(*this, ss);
551  
        fn1_(*this, ss);
552  
    if(st_.empty())
552  
    if(st_.empty())
553  
    {
553  
    {
554  
        done_ = true;
554  
        done_ = true;
555  
        fn0_ = nullptr;
555  
        fn0_ = nullptr;
556  
        p_ = nullptr;
556  
        p_ = nullptr;
557  
    }
557  
    }
558  
    return string_view(
558  
    return string_view(
559  
        dest, ss.used(dest));
559  
        dest, ss.used(dest));
560  
}
560  
}
561  

561  

562  
} // namespace json
562  
} // namespace json
563  
} // namespace boost
563  
} // namespace boost
564  

564  

565  
#ifdef _MSC_VER
565  
#ifdef _MSC_VER
566  
#pragma warning(pop)
566  
#pragma warning(pop)
567  
#endif
567  
#endif
568  

568  

569  
#endif
569  
#endif