Coverage Report

Created: 2026-01-25 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/impl/serializer.ipp
Line
Count
Source
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
//
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)
6
//
7
// Official repository: https://github.com/boostorg/json
8
//
9
10
#ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
11
#define BOOST_JSON_IMPL_SERIALIZER_IPP
12
13
#include <boost/core/detail/static_assert.hpp>
14
#include <boost/json/serializer.hpp>
15
#include <boost/json/detail/format.hpp>
16
#include <boost/json/detail/sse2.hpp>
17
18
#ifdef _MSC_VER
19
#pragma warning(push)
20
#pragma warning(disable: 4127) // conditional expression is constant
21
#endif
22
23
namespace boost {
24
namespace json {
25
namespace detail {
26
27
struct int64_formatter
28
{
29
    std::int64_t i;
30
31
    std::size_t
32
    operator()(char* dst) const noexcept
33
3.68M
    {
34
3.68M
        return format_int64(dst, i);
35
3.68M
    }
36
};
37
38
struct uint64_formatter
39
{
40
    std::uint64_t u;
41
42
    std::size_t
43
    operator()(char* dst) const noexcept
44
24.5k
    {
45
24.5k
        return format_uint64(dst, u);
46
24.5k
    }
47
};
48
49
struct double_formatter
50
{
51
    double d;
52
    bool allow_infinity_and_nan;
53
54
    std::size_t
55
    operator()(char* dst) const noexcept
56
6.42M
    {
57
6.42M
        return format_double(dst, d, allow_infinity_and_nan);
58
6.42M
    }
59
};
60
61
writer::
62
writer(
63
    storage_ptr sp,
64
    unsigned char* buf,
65
    std::size_t buf_size,
66
    serialize_options const& opts) noexcept
67
7.07k
    : st_(
68
7.07k
        std::move(sp),
69
7.07k
        buf,
70
7.07k
        buf_size)
71
7.07k
    , opts_(opts)
72
7.07k
{
73
    // ensure room for \uXXXX escape plus one
74
7.07k
    BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
75
7.07k
}
76
77
bool
78
BOOST_FORCEINLINE
79
write_buffer(writer& w, stream& ss0)
80
5.62k
{
81
5.62k
    local_stream ss(ss0);
82
5.62k
    auto const n = ss.remain();
83
5.62k
    if( n < w.cs0_.remain() )
84
1.16k
    {
85
1.16k
        ss.append(w.cs0_.data(), n);
86
1.16k
        w.cs0_.skip(n);
87
1.16k
        return w.suspend(writer::state::lit);
88
1.16k
    }
89
4.45k
    ss.append( w.cs0_.data(), w.cs0_.remain() );
90
4.45k
    return true;
91
5.62k
}
92
93
template< class F >
94
bool
95
write_buffer(writer& w, stream& ss0, F f)
96
10.1M
{
97
10.1M
    BOOST_ASSERT( w.st_.empty() );
98
99
10.1M
    local_stream ss(ss0);
100
10.1M
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101
10.1M
    {
102
10.1M
        ss.advance( f(ss.data()) );
103
10.1M
        return true;
104
10.1M
    }
105
106
4.37k
    w.cs0_ = { w.buf_, f(w.buf_) };
107
4.37k
    return write_buffer(w, ss);
108
10.1M
}
bool boost::json::detail::write_buffer<boost::json::detail::int64_formatter>(boost::json::detail::writer&, boost::json::detail::stream&, boost::json::detail::int64_formatter)
Line
Count
Source
96
3.68M
{
97
3.68M
    BOOST_ASSERT( w.st_.empty() );
98
99
3.68M
    local_stream ss(ss0);
100
3.68M
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101
3.67M
    {
102
3.67M
        ss.advance( f(ss.data()) );
103
3.67M
        return true;
104
3.67M
    }
105
106
2.45k
    w.cs0_ = { w.buf_, f(w.buf_) };
107
2.45k
    return write_buffer(w, ss);
108
3.68M
}
bool boost::json::detail::write_buffer<boost::json::detail::uint64_formatter>(boost::json::detail::writer&, boost::json::detail::stream&, boost::json::detail::uint64_formatter)
Line
Count
Source
96
24.5k
{
97
24.5k
    BOOST_ASSERT( w.st_.empty() );
98
99
24.5k
    local_stream ss(ss0);
100
24.5k
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101
24.4k
    {
102
24.4k
        ss.advance( f(ss.data()) );
103
24.4k
        return true;
104
24.4k
    }
105
106
167
    w.cs0_ = { w.buf_, f(w.buf_) };
107
167
    return write_buffer(w, ss);
108
24.5k
}
bool boost::json::detail::write_buffer<boost::json::detail::double_formatter>(boost::json::detail::writer&, boost::json::detail::stream&, boost::json::detail::double_formatter)
Line
Count
Source
96
6.42M
{
97
6.42M
    BOOST_ASSERT( w.st_.empty() );
98
99
6.42M
    local_stream ss(ss0);
100
6.42M
    if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101
6.42M
    {
102
6.42M
        ss.advance( f(ss.data()) );
103
6.42M
        return true;
104
6.42M
    }
105
106
1.75k
    w.cs0_ = { w.buf_, f(w.buf_) };
107
1.75k
    return write_buffer(w, ss);
108
6.42M
}
109
110
template<literals Lit>
111
bool
112
write_literal(writer& w, stream& ss)
113
30.2k
{
114
30.2k
    constexpr std::size_t index = literal_index(Lit);
115
30.2k
    constexpr char const* literal = literal_strings[index];
116
30.2k
    constexpr std::size_t sz = literal_sizes[index];
117
118
30.2k
    std::size_t const n = ss.remain();
119
30.2k
    if(BOOST_JSON_LIKELY( n >= sz ))
120
30.2k
    {
121
30.2k
        ss.append( literal, sz );
122
30.2k
        return true;
123
30.2k
    }
124
125
83
    ss.append(literal, n);
126
127
83
    w.cs0_ = {literal + n, sz - n};
128
83
    return w.suspend(writer::state::lit);
129
30.2k
}
bool boost::json::detail::write_literal<(boost::json::detail::literals)1>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
113
15.9k
{
114
15.9k
    constexpr std::size_t index = literal_index(Lit);
115
15.9k
    constexpr char const* literal = literal_strings[index];
116
15.9k
    constexpr std::size_t sz = literal_sizes[index];
117
118
15.9k
    std::size_t const n = ss.remain();
119
15.9k
    if(BOOST_JSON_LIKELY( n >= sz ))
120
15.8k
    {
121
15.8k
        ss.append( literal, sz );
122
15.8k
        return true;
123
15.8k
    }
124
125
26
    ss.append(literal, n);
126
127
26
    w.cs0_ = {literal + n, sz - n};
128
26
    return w.suspend(writer::state::lit);
129
15.9k
}
bool boost::json::detail::write_literal<(boost::json::detail::literals)2>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
113
6.87k
{
114
6.87k
    constexpr std::size_t index = literal_index(Lit);
115
6.87k
    constexpr char const* literal = literal_strings[index];
116
6.87k
    constexpr std::size_t sz = literal_sizes[index];
117
118
6.87k
    std::size_t const n = ss.remain();
119
6.87k
    if(BOOST_JSON_LIKELY( n >= sz ))
120
6.85k
    {
121
6.85k
        ss.append( literal, sz );
122
6.85k
        return true;
123
6.85k
    }
124
125
26
    ss.append(literal, n);
126
127
26
    w.cs0_ = {literal + n, sz - n};
128
26
    return w.suspend(writer::state::lit);
129
6.87k
}
bool boost::json::detail::write_literal<(boost::json::detail::literals)0>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
113
7.49k
{
114
7.49k
    constexpr std::size_t index = literal_index(Lit);
115
7.49k
    constexpr char const* literal = literal_strings[index];
116
7.49k
    constexpr std::size_t sz = literal_sizes[index];
117
118
7.49k
    std::size_t const n = ss.remain();
119
7.49k
    if(BOOST_JSON_LIKELY( n >= sz ))
120
7.46k
    {
121
7.46k
        ss.append( literal, sz );
122
7.46k
        return true;
123
7.46k
    }
124
125
31
    ss.append(literal, n);
126
127
31
    w.cs0_ = {literal + n, sz - n};
128
31
    return w.suspend(writer::state::lit);
129
7.49k
}
130
131
bool
132
write_true(writer& w, stream& ss)
133
15.9k
{
134
15.9k
    return write_literal<literals::true_>(w, ss);
135
15.9k
}
136
137
bool
138
write_false(writer& w, stream& ss)
139
6.87k
{
140
6.87k
    return write_literal<literals::false_>(w, ss);
141
6.87k
}
142
143
bool
144
write_null(writer& w, stream& ss)
145
7.49k
{
146
7.49k
    return write_literal<literals::null>(w, ss);
147
7.49k
}
148
149
bool
150
write_int64(writer& w, stream& ss0, std::int64_t i)
151
3.68M
{
152
3.68M
    return write_buffer( w, ss0, int64_formatter{i} );
153
3.68M
}
154
155
bool
156
write_uint64(writer& w, stream& ss0, std::uint64_t u)
157
24.5k
{
158
24.5k
    return write_buffer( w, ss0, uint64_formatter{u} );
159
24.5k
}
160
161
bool
162
write_double(writer& w, stream& ss0, double d)
163
6.42M
{
164
6.42M
    return write_buffer(
165
6.42M
        w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
166
6.42M
}
167
168
bool
169
resume_buffer(writer& w, stream& ss0)
170
1.24k
{
171
1.24k
    BOOST_ASSERT( !w.st_.empty() );
172
1.24k
    writer::state st;
173
1.24k
    w.st_.pop(st);
174
1.24k
    BOOST_ASSERT(st == writer::state::lit);
175
176
1.24k
    return write_buffer(w, ss0);
177
1.24k
}
178
179
template<bool StackEmpty>
180
bool
181
do_write_string(writer& w, stream& ss0)
182
31.4k
{
183
31.4k
    local_stream ss(ss0);
184
31.4k
    local_const_stream cs(w.cs0_);
185
31.4k
    if(! StackEmpty && ! w.st_.empty())
186
1.10k
    {
187
1.10k
        writer::state st;
188
1.10k
        w.st_.pop(st);
189
1.10k
        switch(st)
190
1.10k
        {
191
0
        default:
192
84
        case writer::state::str1: goto do_str1;
193
142
        case writer::state::str2: goto do_str2;
194
673
        case writer::state::str3: goto do_str3;
195
44
        case writer::state::esc1: goto do_esc1;
196
31
        case writer::state::utf1: goto do_utf1;
197
35
        case writer::state::utf2: goto do_utf2;
198
28
        case writer::state::utf3: goto do_utf3;
199
35
        case writer::state::utf4: goto do_utf4;
200
37
        case writer::state::utf5: goto do_utf5;
201
1.10k
        }
202
1.10k
    }
203
30.3k
    static constexpr char hex[] = "0123456789abcdef";
204
30.3k
    static constexpr char esc[] =
205
30.3k
        "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
206
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
214
    // opening quote
215
30.4k
do_str1:
216
30.4k
    if(BOOST_JSON_LIKELY(ss))
217
30.3k
        ss.append('\x22'); // '"'
218
84
    else
219
84
        return w.suspend(writer::state::str1);
220
221
    // fast loop,
222
    // copy unescaped
223
30.5k
do_str2:
224
30.5k
    if(BOOST_JSON_LIKELY(ss))
225
30.4k
    {
226
30.4k
        std::size_t n = cs.remain();
227
30.4k
        if(BOOST_JSON_LIKELY(n > 0))
228
19.8k
        {
229
19.8k
            if(ss.remain() > n)
230
19.3k
                n = detail::count_unescaped(
231
19.3k
                    cs.data(), n);
232
493
            else
233
493
                n = detail::count_unescaped(
234
493
                    cs.data(), ss.remain());
235
19.8k
            if(n > 0)
236
9.60k
            {
237
9.60k
                ss.append(cs.data(), n);
238
9.60k
                cs.skip(n);
239
9.60k
                if(! ss)
240
110
                    return w.suspend(writer::state::str2);
241
9.60k
            }
242
19.8k
        }
243
10.5k
        else
244
10.5k
        {
245
10.5k
            ss.append('\x22'); // '"'
246
10.5k
            return true;
247
10.5k
        }
248
30.4k
    }
249
32
    else
250
32
    {
251
32
        return w.suspend(writer::state::str2);
252
32
    }
253
254
    // slow loop,
255
    // handle escapes
256
20.6k
do_str3:
257
20.6k
    while(BOOST_JSON_LIKELY(ss))
258
29.5M
    {
259
29.5M
        if(BOOST_JSON_LIKELY(cs))
260
29.4M
        {
261
29.4M
            auto const ch = *cs;
262
29.4M
            auto const c = esc[static_cast<
263
29.4M
                unsigned char>(ch)];
264
29.4M
            ++cs;
265
29.4M
            if(! c)
266
28.9M
            {
267
28.9M
                ss.append(ch);
268
28.9M
            }
269
503k
            else if(c != 'u')
270
376k
            {
271
376k
                ss.append('\\');
272
376k
                if(BOOST_JSON_LIKELY(ss))
273
376k
                {
274
376k
                    ss.append(c);
275
376k
                }
276
44
                else
277
44
                {
278
44
                    w.buf_[0] = c;
279
44
                    return w.suspend(
280
44
                        writer::state::esc1);
281
44
                }
282
376k
            }
283
126k
            else
284
126k
            {
285
126k
                if(BOOST_JSON_LIKELY(
286
126k
                    ss.remain() >= 6))
287
126k
                {
288
126k
                    ss.append("\\u00", 4);
289
126k
                    ss.append(hex[static_cast<
290
126k
                        unsigned char>(ch) >> 4]);
291
126k
                    ss.append(hex[static_cast<
292
126k
                        unsigned char>(ch) & 15]);
293
126k
                }
294
166
                else
295
166
                {
296
166
                    ss.append('\\');
297
166
                    w.buf_[0] = hex[static_cast<
298
166
                        unsigned char>(ch) >> 4];
299
166
                    w.buf_[1] = hex[static_cast<
300
166
                        unsigned char>(ch) & 15];
301
166
                    goto do_utf1;
302
166
                }
303
126k
            }
304
29.4M
        }
305
19.7k
        else
306
19.7k
        {
307
19.7k
            ss.append('\x22'); // '"'
308
19.7k
            return true;
309
19.7k
        }
310
29.5M
    }
311
673
    return w.suspend(writer::state::str3);
312
313
44
do_esc1:
314
44
    BOOST_ASSERT(ss);
315
44
    ss.append(w.buf_[0]);
316
44
    goto do_str3;
317
318
197
do_utf1:
319
197
    if(BOOST_JSON_LIKELY(ss))
320
166
        ss.append('u');
321
31
    else
322
31
        return w.suspend(writer::state::utf1);
323
201
do_utf2:
324
201
    if(BOOST_JSON_LIKELY(ss))
325
166
        ss.append('0');
326
35
    else
327
35
        return w.suspend(writer::state::utf2);
328
194
do_utf3:
329
194
    if(BOOST_JSON_LIKELY(ss))
330
166
        ss.append('0');
331
28
    else
332
28
        return w.suspend(writer::state::utf3);
333
201
do_utf4:
334
201
    if(BOOST_JSON_LIKELY(ss))
335
166
        ss.append(w.buf_[0]);
336
35
    else
337
35
        return w.suspend(writer::state::utf4);
338
203
do_utf5:
339
203
    if(BOOST_JSON_LIKELY(ss))
340
166
        ss.append(w.buf_[1]);
341
37
    else
342
37
        return w.suspend(writer::state::utf5);
343
166
    goto do_str3;
344
203
}
bool boost::json::detail::do_write_string<true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
182
30.3k
{
183
30.3k
    local_stream ss(ss0);
184
30.3k
    local_const_stream cs(w.cs0_);
185
30.3k
    if(! StackEmpty && ! w.st_.empty())
186
0
    {
187
0
        writer::state st;
188
0
        w.st_.pop(st);
189
0
        switch(st)
190
0
        {
191
0
        default:
192
0
        case writer::state::str1: goto do_str1;
193
0
        case writer::state::str2: goto do_str2;
194
0
        case writer::state::str3: goto do_str3;
195
0
        case writer::state::esc1: goto do_esc1;
196
0
        case writer::state::utf1: goto do_utf1;
197
0
        case writer::state::utf2: goto do_utf2;
198
0
        case writer::state::utf3: goto do_utf3;
199
0
        case writer::state::utf4: goto do_utf4;
200
0
        case writer::state::utf5: goto do_utf5;
201
0
        }
202
0
    }
203
30.3k
    static constexpr char hex[] = "0123456789abcdef";
204
30.3k
    static constexpr char esc[] =
205
30.3k
        "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
206
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
30.3k
        "\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
214
    // opening quote
215
30.3k
do_str1:
216
30.3k
    if(BOOST_JSON_LIKELY(ss))
217
30.2k
        ss.append('\x22'); // '"'
218
84
    else
219
84
        return w.suspend(writer::state::str1);
220
221
    // fast loop,
222
    // copy unescaped
223
30.2k
do_str2:
224
30.2k
    if(BOOST_JSON_LIKELY(ss))
225
30.2k
    {
226
30.2k
        std::size_t n = cs.remain();
227
30.2k
        if(BOOST_JSON_LIKELY(n > 0))
228
19.6k
        {
229
19.6k
            if(ss.remain() > n)
230
19.2k
                n = detail::count_unescaped(
231
19.2k
                    cs.data(), n);
232
420
            else
233
420
                n = detail::count_unescaped(
234
420
                    cs.data(), ss.remain());
235
19.6k
            if(n > 0)
236
9.44k
            {
237
9.44k
                ss.append(cs.data(), n);
238
9.44k
                cs.skip(n);
239
9.44k
                if(! ss)
240
99
                    return w.suspend(writer::state::str2);
241
9.44k
            }
242
19.6k
        }
243
10.5k
        else
244
10.5k
        {
245
10.5k
            ss.append('\x22'); // '"'
246
10.5k
            return true;
247
10.5k
        }
248
30.2k
    }
249
32
    else
250
32
    {
251
32
        return w.suspend(writer::state::str2);
252
32
    }
253
254
    // slow loop,
255
    // handle escapes
256
19.5k
do_str3:
257
19.5k
    while(BOOST_JSON_LIKELY(ss))
258
1.90M
    {
259
1.90M
        if(BOOST_JSON_LIKELY(cs))
260
1.88M
        {
261
1.88M
            auto const ch = *cs;
262
1.88M
            auto const c = esc[static_cast<
263
1.88M
                unsigned char>(ch)];
264
1.88M
            ++cs;
265
1.88M
            if(! c)
266
1.54M
            {
267
1.54M
                ss.append(ch);
268
1.54M
            }
269
342k
            else if(c != 'u')
270
273k
            {
271
273k
                ss.append('\\');
272
273k
                if(BOOST_JSON_LIKELY(ss))
273
273k
                {
274
273k
                    ss.append(c);
275
273k
                }
276
29
                else
277
29
                {
278
29
                    w.buf_[0] = c;
279
29
                    return w.suspend(
280
29
                        writer::state::esc1);
281
29
                }
282
273k
            }
283
68.9k
            else
284
68.9k
            {
285
68.9k
                if(BOOST_JSON_LIKELY(
286
68.9k
                    ss.remain() >= 6))
287
68.8k
                {
288
68.8k
                    ss.append("\\u00", 4);
289
68.8k
                    ss.append(hex[static_cast<
290
68.8k
                        unsigned char>(ch) >> 4]);
291
68.8k
                    ss.append(hex[static_cast<
292
68.8k
                        unsigned char>(ch) & 15]);
293
68.8k
                }
294
90
                else
295
90
                {
296
90
                    ss.append('\\');
297
90
                    w.buf_[0] = hex[static_cast<
298
90
                        unsigned char>(ch) >> 4];
299
90
                    w.buf_[1] = hex[static_cast<
300
90
                        unsigned char>(ch) & 15];
301
90
                    goto do_utf1;
302
90
                }
303
68.9k
            }
304
1.88M
        }
305
19.2k
        else
306
19.2k
        {
307
19.2k
            ss.append('\x22'); // '"'
308
19.2k
            return true;
309
19.2k
        }
310
1.90M
    }
311
239
    return w.suspend(writer::state::str3);
312
313
0
do_esc1:
314
0
    BOOST_ASSERT(ss);
315
0
    ss.append(w.buf_[0]);
316
0
    goto do_str3;
317
318
90
do_utf1:
319
90
    if(BOOST_JSON_LIKELY(ss))
320
73
        ss.append('u');
321
17
    else
322
17
        return w.suspend(writer::state::utf1);
323
73
do_utf2:
324
73
    if(BOOST_JSON_LIKELY(ss))
325
55
        ss.append('0');
326
18
    else
327
18
        return w.suspend(writer::state::utf2);
328
55
do_utf3:
329
55
    if(BOOST_JSON_LIKELY(ss))
330
39
        ss.append('0');
331
16
    else
332
16
        return w.suspend(writer::state::utf3);
333
39
do_utf4:
334
39
    if(BOOST_JSON_LIKELY(ss))
335
19
        ss.append(w.buf_[0]);
336
20
    else
337
20
        return w.suspend(writer::state::utf4);
338
19
do_utf5:
339
19
    if(BOOST_JSON_LIKELY(ss))
340
0
        ss.append(w.buf_[1]);
341
19
    else
342
19
        return w.suspend(writer::state::utf5);
343
0
    goto do_str3;
344
19
}
bool boost::json::detail::do_write_string<false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
182
1.10k
{
183
1.10k
    local_stream ss(ss0);
184
1.10k
    local_const_stream cs(w.cs0_);
185
1.10k
    if(! StackEmpty && ! w.st_.empty())
186
1.10k
    {
187
1.10k
        writer::state st;
188
1.10k
        w.st_.pop(st);
189
1.10k
        switch(st)
190
1.10k
        {
191
0
        default:
192
84
        case writer::state::str1: goto do_str1;
193
142
        case writer::state::str2: goto do_str2;
194
673
        case writer::state::str3: goto do_str3;
195
44
        case writer::state::esc1: goto do_esc1;
196
31
        case writer::state::utf1: goto do_utf1;
197
35
        case writer::state::utf2: goto do_utf2;
198
28
        case writer::state::utf3: goto do_utf3;
199
35
        case writer::state::utf4: goto do_utf4;
200
37
        case writer::state::utf5: goto do_utf5;
201
1.10k
        }
202
1.10k
    }
203
0
    static constexpr char hex[] = "0123456789abcdef";
204
0
    static constexpr char esc[] =
205
0
        "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\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\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\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\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\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\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\0";
213
214
    // opening quote
215
84
do_str1:
216
84
    if(BOOST_JSON_LIKELY(ss))
217
84
        ss.append('\x22'); // '"'
218
0
    else
219
0
        return w.suspend(writer::state::str1);
220
221
    // fast loop,
222
    // copy unescaped
223
226
do_str2:
224
226
    if(BOOST_JSON_LIKELY(ss))
225
226
    {
226
226
        std::size_t n = cs.remain();
227
226
        if(BOOST_JSON_LIKELY(n > 0))
228
200
        {
229
200
            if(ss.remain() > n)
230
127
                n = detail::count_unescaped(
231
127
                    cs.data(), n);
232
73
            else
233
73
                n = detail::count_unescaped(
234
73
                    cs.data(), ss.remain());
235
200
            if(n > 0)
236
163
            {
237
163
                ss.append(cs.data(), n);
238
163
                cs.skip(n);
239
163
                if(! ss)
240
11
                    return w.suspend(writer::state::str2);
241
163
            }
242
200
        }
243
26
        else
244
26
        {
245
26
            ss.append('\x22'); // '"'
246
26
            return true;
247
26
        }
248
226
    }
249
0
    else
250
0
    {
251
0
        return w.suspend(writer::state::str2);
252
0
    }
253
254
    // slow loop,
255
    // handle escapes
256
1.07k
do_str3:
257
1.07k
    while(BOOST_JSON_LIKELY(ss))
258
27.6M
    {
259
27.6M
        if(BOOST_JSON_LIKELY(cs))
260
27.6M
        {
261
27.6M
            auto const ch = *cs;
262
27.6M
            auto const c = esc[static_cast<
263
27.6M
                unsigned char>(ch)];
264
27.6M
            ++cs;
265
27.6M
            if(! c)
266
27.4M
            {
267
27.4M
                ss.append(ch);
268
27.4M
            }
269
161k
            else if(c != 'u')
270
103k
            {
271
103k
                ss.append('\\');
272
103k
                if(BOOST_JSON_LIKELY(ss))
273
103k
                {
274
103k
                    ss.append(c);
275
103k
                }
276
15
                else
277
15
                {
278
15
                    w.buf_[0] = c;
279
15
                    return w.suspend(
280
15
                        writer::state::esc1);
281
15
                }
282
103k
            }
283
57.9k
            else
284
57.9k
            {
285
57.9k
                if(BOOST_JSON_LIKELY(
286
57.9k
                    ss.remain() >= 6))
287
57.8k
                {
288
57.8k
                    ss.append("\\u00", 4);
289
57.8k
                    ss.append(hex[static_cast<
290
57.8k
                        unsigned char>(ch) >> 4]);
291
57.8k
                    ss.append(hex[static_cast<
292
57.8k
                        unsigned char>(ch) & 15]);
293
57.8k
                }
294
76
                else
295
76
                {
296
76
                    ss.append('\\');
297
76
                    w.buf_[0] = hex[static_cast<
298
76
                        unsigned char>(ch) >> 4];
299
76
                    w.buf_[1] = hex[static_cast<
300
76
                        unsigned char>(ch) & 15];
301
76
                    goto do_utf1;
302
76
                }
303
57.9k
            }
304
27.6M
        }
305
547
        else
306
547
        {
307
547
            ss.append('\x22'); // '"'
308
547
            return true;
309
547
        }
310
27.6M
    }
311
434
    return w.suspend(writer::state::str3);
312
313
44
do_esc1:
314
44
    BOOST_ASSERT(ss);
315
44
    ss.append(w.buf_[0]);
316
44
    goto do_str3;
317
318
107
do_utf1:
319
107
    if(BOOST_JSON_LIKELY(ss))
320
93
        ss.append('u');
321
14
    else
322
14
        return w.suspend(writer::state::utf1);
323
128
do_utf2:
324
128
    if(BOOST_JSON_LIKELY(ss))
325
111
        ss.append('0');
326
17
    else
327
17
        return w.suspend(writer::state::utf2);
328
139
do_utf3:
329
139
    if(BOOST_JSON_LIKELY(ss))
330
127
        ss.append('0');
331
12
    else
332
12
        return w.suspend(writer::state::utf3);
333
162
do_utf4:
334
162
    if(BOOST_JSON_LIKELY(ss))
335
147
        ss.append(w.buf_[0]);
336
15
    else
337
15
        return w.suspend(writer::state::utf4);
338
184
do_utf5:
339
184
    if(BOOST_JSON_LIKELY(ss))
340
166
        ss.append(w.buf_[1]);
341
18
    else
342
18
        return w.suspend(writer::state::utf5);
343
166
    goto do_str3;
344
184
}
345
346
bool
347
write_string(writer& w, stream& ss0)
348
13.4k
{
349
13.4k
    return do_write_string<true>(w, ss0);
350
13.4k
}
351
352
bool
353
resume_string(writer& w, stream& ss0)
354
365
{
355
365
    return do_write_string<false>(w, ss0);
356
365
}
357
358
template<bool StackEmpty>
359
bool
360
write_value(writer& w, stream& ss);
361
362
template< class T, bool StackEmpty >
363
BOOST_FORCEINLINE
364
bool
365
write_impl(no_conversion_tag, writer& w, stream& ss)
366
10.2M
{
367
10.2M
    return write_value<StackEmpty>(w, ss);
368
10.2M
}
bool boost::json::detail::write_impl<boost::json::value, true>(boost::json::detail::no_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
366
1.03M
{
367
1.03M
    return write_value<StackEmpty>(w, ss);
368
1.03M
}
bool boost::json::detail::write_impl<boost::json::value, false>(boost::json::detail::no_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
366
9.14M
{
367
9.14M
    return write_value<StackEmpty>(w, ss);
368
9.14M
}
bool boost::json::detail::write_impl<boost::json::value&, true>(boost::json::detail::no_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
366
11.0k
{
367
11.0k
    return write_value<StackEmpty>(w, ss);
368
11.0k
}
bool boost::json::detail::write_impl<boost::json::value&, false>(boost::json::detail::no_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
366
3.59k
{
367
3.59k
    return write_value<StackEmpty>(w, ss);
368
3.59k
}
369
370
template<bool StackEmpty>
371
bool
372
write_array(writer& w, stream& ss)
373
21.2k
{
374
21.2k
    return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375
21.2k
}
bool boost::json::detail::write_array<true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
373
14.7k
{
374
14.7k
    return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375
14.7k
}
bool boost::json::detail::write_array<false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
373
6.46k
{
374
6.46k
    return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375
6.46k
}
376
377
template<bool StackEmpty>
378
bool
379
write_object(writer& w, stream& ss)
380
7.63k
{
381
7.63k
    return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382
7.63k
}
bool boost::json::detail::write_object<true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
380
5.92k
{
381
5.92k
    return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382
5.92k
}
bool boost::json::detail::write_object<false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
380
1.70k
{
381
1.70k
    return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382
1.70k
}
383
384
template<bool StackEmpty>
385
bool
386
write_value(writer& w, stream& ss)
387
10.2M
{
388
10.2M
    if(StackEmpty || w.st_.empty())
389
10.2M
    {
390
10.2M
        BOOST_ASSERT( w.p_ );
391
10.2M
        auto const pv = reinterpret_cast<value const*>(w.p_);
392
10.2M
        switch(pv->kind())
393
10.2M
        {
394
0
        default:
395
5.92k
        case kind::object:
396
5.92k
            w.p_ = &pv->get_object();
397
5.92k
            return write_object<true>(w, ss);
398
399
14.7k
        case kind::array:
400
14.7k
            w.p_ = &pv->get_array();
401
14.7k
            return write_array<true>(w, ss);
402
403
16.9k
        case kind::string:
404
16.9k
        {
405
16.9k
            auto const& js = pv->get_string();
406
16.9k
            w.cs0_ = { js.data(), js.size() };
407
16.9k
            return do_write_string<true>(w, ss);
408
0
        }
409
410
3.68M
        case kind::int64:
411
3.68M
            return write_int64( w, ss, pv->get_int64() );
412
24.5k
        case kind::uint64:
413
24.5k
            return write_uint64( w, ss, pv->get_uint64() );
414
6.42M
        case kind::double_:
415
6.42M
            return write_double( w, ss, pv->get_double() );
416
417
22.7k
        case kind::bool_:
418
22.7k
            if( pv->get_bool() )
419
15.9k
                return write_true(w, ss);
420
6.87k
            else
421
6.87k
                return write_false(w, ss);
422
423
7.49k
        case kind::null:
424
7.49k
            return write_null(w, ss);
425
10.2M
        }
426
10.2M
    }
427
10.1k
    else
428
10.1k
    {
429
10.1k
        writer::state st;
430
10.1k
        w.st_.peek(st);
431
10.1k
        switch(st)
432
10.1k
        {
433
0
        default:
434
1.24k
        case writer::state::lit:
435
1.24k
            return resume_buffer(w, ss);
436
437
139
        case writer::state::str1: case writer::state::str2:
438
588
        case writer::state::str3: case writer::state::esc1:
439
652
        case writer::state::utf1: case writer::state::utf2:
440
712
        case writer::state::utf3: case writer::state::utf4:
441
744
        case writer::state::utf5:
442
744
            return do_write_string<false>(w, ss);
443
444
6.24k
        case writer::state::arr1: case writer::state::arr2:
445
6.46k
        case writer::state::arr3: case writer::state::arr4:
446
6.46k
            return write_array<StackEmpty>(w, ss);
447
448
382
        case writer::state::obj1: case writer::state::obj2:
449
1.65k
        case writer::state::obj3: case writer::state::obj4:
450
1.70k
        case writer::state::obj5: case writer::state::obj6:
451
1.70k
            return write_object<StackEmpty>(w, ss);
452
10.1k
        }
453
10.1k
    }
454
10.2M
}
bool boost::json::detail::write_value<true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
387
1.05M
{
388
1.05M
    if(StackEmpty || w.st_.empty())
389
1.05M
    {
390
1.05M
        BOOST_ASSERT( w.p_ );
391
1.05M
        auto const pv = reinterpret_cast<value const*>(w.p_);
392
1.05M
        switch(pv->kind())
393
1.05M
        {
394
0
        default:
395
4.27k
        case kind::object:
396
4.27k
            w.p_ = &pv->get_object();
397
4.27k
            return write_object<true>(w, ss);
398
399
11.0k
        case kind::array:
400
11.0k
            w.p_ = &pv->get_array();
401
11.0k
            return write_array<true>(w, ss);
402
403
3.92k
        case kind::string:
404
3.92k
        {
405
3.92k
            auto const& js = pv->get_string();
406
3.92k
            w.cs0_ = { js.data(), js.size() };
407
3.92k
            return do_write_string<true>(w, ss);
408
0
        }
409
410
187k
        case kind::int64:
411
187k
            return write_int64( w, ss, pv->get_int64() );
412
19.6k
        case kind::uint64:
413
19.6k
            return write_uint64( w, ss, pv->get_uint64() );
414
810k
        case kind::double_:
415
810k
            return write_double( w, ss, pv->get_double() );
416
417
14.6k
        case kind::bool_:
418
14.6k
            if( pv->get_bool() )
419
12.0k
                return write_true(w, ss);
420
2.62k
            else
421
2.62k
                return write_false(w, ss);
422
423
3.74k
        case kind::null:
424
3.74k
            return write_null(w, ss);
425
1.05M
        }
426
1.05M
    }
427
0
    else
428
0
    {
429
0
        writer::state st;
430
0
        w.st_.peek(st);
431
0
        switch(st)
432
0
        {
433
0
        default:
434
0
        case writer::state::lit:
435
0
            return resume_buffer(w, ss);
436
437
0
        case writer::state::str1: case writer::state::str2:
438
0
        case writer::state::str3: case writer::state::esc1:
439
0
        case writer::state::utf1: case writer::state::utf2:
440
0
        case writer::state::utf3: case writer::state::utf4:
441
0
        case writer::state::utf5:
442
0
            return do_write_string<false>(w, ss);
443
444
0
        case writer::state::arr1: case writer::state::arr2:
445
0
        case writer::state::arr3: case writer::state::arr4:
446
0
            return write_array<StackEmpty>(w, ss);
447
448
0
        case writer::state::obj1: case writer::state::obj2:
449
0
        case writer::state::obj3: case writer::state::obj4:
450
0
        case writer::state::obj5: case writer::state::obj6:
451
0
            return write_object<StackEmpty>(w, ss);
452
0
        }
453
0
    }
454
1.05M
}
bool boost::json::detail::write_value<false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
387
9.15M
{
388
9.15M
    if(StackEmpty || w.st_.empty())
389
9.14M
    {
390
9.14M
        BOOST_ASSERT( w.p_ );
391
9.14M
        auto const pv = reinterpret_cast<value const*>(w.p_);
392
9.14M
        switch(pv->kind())
393
9.14M
        {
394
0
        default:
395
1.64k
        case kind::object:
396
1.64k
            w.p_ = &pv->get_object();
397
1.64k
            return write_object<true>(w, ss);
398
399
3.75k
        case kind::array:
400
3.75k
            w.p_ = &pv->get_array();
401
3.75k
            return write_array<true>(w, ss);
402
403
13.0k
        case kind::string:
404
13.0k
        {
405
13.0k
            auto const& js = pv->get_string();
406
13.0k
            w.cs0_ = { js.data(), js.size() };
407
13.0k
            return do_write_string<true>(w, ss);
408
0
        }
409
410
3.49M
        case kind::int64:
411
3.49M
            return write_int64( w, ss, pv->get_int64() );
412
4.98k
        case kind::uint64:
413
4.98k
            return write_uint64( w, ss, pv->get_uint64() );
414
5.61M
        case kind::double_:
415
5.61M
            return write_double( w, ss, pv->get_double() );
416
417
8.10k
        case kind::bool_:
418
8.10k
            if( pv->get_bool() )
419
3.85k
                return write_true(w, ss);
420
4.24k
            else
421
4.24k
                return write_false(w, ss);
422
423
3.74k
        case kind::null:
424
3.74k
            return write_null(w, ss);
425
9.14M
        }
426
9.14M
    }
427
10.1k
    else
428
10.1k
    {
429
10.1k
        writer::state st;
430
10.1k
        w.st_.peek(st);
431
10.1k
        switch(st)
432
10.1k
        {
433
0
        default:
434
1.24k
        case writer::state::lit:
435
1.24k
            return resume_buffer(w, ss);
436
437
139
        case writer::state::str1: case writer::state::str2:
438
588
        case writer::state::str3: case writer::state::esc1:
439
652
        case writer::state::utf1: case writer::state::utf2:
440
712
        case writer::state::utf3: case writer::state::utf4:
441
744
        case writer::state::utf5:
442
744
            return do_write_string<false>(w, ss);
443
444
6.24k
        case writer::state::arr1: case writer::state::arr2:
445
6.46k
        case writer::state::arr3: case writer::state::arr4:
446
6.46k
            return write_array<StackEmpty>(w, ss);
447
448
382
        case writer::state::obj1: case writer::state::obj2:
449
1.65k
        case writer::state::obj3: case writer::state::obj4:
450
1.70k
        case writer::state::obj5: case writer::state::obj6:
451
1.70k
            return write_object<StackEmpty>(w, ss);
452
10.1k
        }
453
10.1k
    }
454
9.15M
}
455
456
} // namespace detail
457
458
serializer::
459
serializer(serialize_options const& opts) noexcept
460
0
    : serializer({}, nullptr, 0, opts)
461
0
{}
462
463
serializer::
464
serializer(
465
    storage_ptr sp,
466
    unsigned char* buf,
467
    std::size_t buf_size,
468
    serialize_options const& opts) noexcept
469
7.07k
    : detail::writer(std::move(sp), buf, buf_size, opts)
470
7.07k
{}
471
472
void
473
serializer::
474
reset(value const* p) noexcept
475
7.07k
{
476
7.07k
    p_ = p;
477
7.07k
    fn0_ = &detail::write_value<true>;
478
7.07k
    fn1_ = &detail::write_value<false>;
479
7.07k
    st_.clear();
480
7.07k
    done_ = false;
481
7.07k
}
482
483
void
484
serializer::
485
reset(array const* p) noexcept
486
0
{
487
0
    p_ = p;
488
0
    fn0_ = &detail::write_array<true>;
489
0
    fn1_ = &detail::write_array<false>;
490
0
    st_.clear();
491
0
    done_ = false;
492
0
}
493
494
void
495
serializer::
496
reset(object const* p) noexcept
497
0
{
498
0
    p_ = p;
499
0
    fn0_ = &detail::write_object<true>;
500
0
    fn1_ = &detail::write_object<false>;
501
0
    st_.clear();
502
0
    done_ = false;
503
0
}
504
505
void
506
serializer::
507
reset(string const* p) noexcept
508
0
{
509
0
    cs0_ = { p->data(), p->size() };
510
0
    fn0_ = &detail::do_write_string<true>;
511
0
    fn1_ = &detail::do_write_string<false>;
512
0
    st_.clear();
513
0
    done_ = false;
514
0
}
515
516
void
517
serializer::
518
reset(string_view sv) noexcept
519
0
{
520
0
    cs0_ = { sv.data(), sv.size() };
521
0
    fn0_ = &detail::do_write_string<true>;
522
0
    fn1_ = &detail::do_write_string<false>;
523
0
    st_.clear();
524
0
    done_ = false;
525
0
}
526
527
void
528
serializer::reset(std::nullptr_t) noexcept
529
0
{
530
0
    p_ = nullptr;
531
0
    fn0_ = &detail::write_impl<std::nullptr_t, true>;
532
0
    fn1_ = &detail::write_impl<std::nullptr_t, false>;
533
0
    st_.clear();
534
0
    done_ = false;
535
0
}
536
537
string_view
538
serializer::
539
read(char* dest, std::size_t size)
540
9.75k
{
541
9.75k
    if( !fn0_ )
542
0
        reset(nullptr);
543
544
9.75k
    if(BOOST_JSON_UNLIKELY(size == 0))
545
0
        return {dest, 0};
546
547
9.75k
    detail::stream ss(dest, size);
548
9.75k
    if(st_.empty())
549
7.07k
        fn0_(*this, ss);
550
2.67k
    else
551
2.67k
        fn1_(*this, ss);
552
9.75k
    if(st_.empty())
553
7.07k
    {
554
7.07k
        done_ = true;
555
7.07k
        fn0_ = nullptr;
556
7.07k
        p_ = nullptr;
557
7.07k
    }
558
9.75k
    return string_view(
559
9.75k
        dest, ss.used(dest));
560
9.75k
}
561
562
} // namespace json
563
} // namespace boost
564
565
#ifdef _MSC_VER
566
#pragma warning(pop)
567
#endif
568
569
#endif