Coverage Report

Created: 2025-11-08 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/impl/serializer.hpp
Line
Count
Source
1
//
2
// Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru)
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_HPP
11
#define BOOST_JSON_IMPL_SERIALIZER_HPP
12
13
#include <boost/core/detail/static_assert.hpp>
14
#include <boost/describe/enum_to_string.hpp>
15
#include <boost/json/conversion.hpp>
16
#include <cstddef>
17
18
namespace boost {
19
namespace json {
20
namespace detail {
21
22
enum class writer::state : char
23
{
24
    str1, str2, str3, esc1, utf1,
25
    utf2, utf3, utf4, utf5,
26
    lit,
27
    arr1, arr2, arr3, arr4,
28
    obj1, obj2, obj3, obj4, obj5, obj6
29
};
30
31
bool
32
writer::
33
suspend(state st)
34
2.38k
{
35
2.38k
    st_.push(st);
36
2.38k
    return false;
37
2.38k
}
38
39
template<class U, class T>
40
bool
41
writer::
42
suspend(state st, U u, T const* pt)
43
8.37k
{
44
8.37k
    st_.push(pt);
45
8.37k
    st_.push(u);
46
8.37k
    st_.push(st);
47
8.37k
    return false;
48
8.37k
}
bool boost::json::detail::writer::suspend<boost::json::value const*, boost::json::array>(boost::json::detail::writer::state, boost::json::value const*, boost::json::array const*)
Line
Count
Source
43
6.31k
{
44
6.31k
    st_.push(pt);
45
6.31k
    st_.push(u);
46
6.31k
    st_.push(st);
47
6.31k
    return false;
48
6.31k
}
bool boost::json::detail::writer::suspend<boost::json::key_value_pair const*, boost::json::object>(boost::json::detail::writer::state, boost::json::key_value_pair const*, boost::json::object const*)
Line
Count
Source
43
2.05k
{
44
2.05k
    st_.push(pt);
45
2.05k
    st_.push(u);
46
2.05k
    st_.push(st);
47
2.05k
    return false;
48
2.05k
}
49
50
template<class T, bool StackEmpty>
51
bool
52
write_impl(writer& w, stream& ss);
53
54
template<class T, bool StackEmpty>
55
BOOST_FORCEINLINE
56
bool
57
write_impl(null_like_conversion_tag, writer& w, stream& ss)
58
0
{
59
#if defined(_MSC_VER)
60
# pragma warning( push )
61
# pragma warning( disable : 4127 )
62
#endif
63
0
    if( StackEmpty || w.st_.empty() )
64
0
        return write_null(w, ss);
65
#if defined(_MSC_VER)
66
# pragma warning( pop )
67
#endif
68
0
    return resume_buffer(w, ss);
69
0
}
Unexecuted instantiation: bool boost::json::detail::write_impl<decltype(nullptr), true>(boost::json::detail::null_like_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Unexecuted instantiation: bool boost::json::detail::write_impl<decltype(nullptr), false>(boost::json::detail::null_like_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
70
71
template<class T, bool StackEmpty>
72
BOOST_FORCEINLINE
73
bool
74
write_impl(bool_conversion_tag, writer& w, stream& ss)
75
{
76
    BOOST_ASSERT( w.p_ );
77
    auto const t = *reinterpret_cast<T const*>(w.p_);
78
79
#if defined(_MSC_VER)
80
# pragma warning( push )
81
# pragma warning( disable : 4127 )
82
#endif
83
    if( StackEmpty || w.st_.empty() )
84
#if defined(_MSC_VER)
85
# pragma warning( pop )
86
#endif
87
    {
88
        if( t )
89
            return write_true(w, ss);
90
        else
91
            return write_false(w, ss);
92
    }
93
94
    return resume_buffer(w, ss);
95
}
96
97
template<class T, bool StackEmpty>
98
BOOST_FORCEINLINE
99
bool
100
write_impl(integral_conversion_tag, writer& w, stream& ss0)
101
{
102
#if defined(_MSC_VER)
103
# pragma warning( push )
104
# pragma warning( disable : 4127 )
105
#endif
106
    if( StackEmpty || w.st_.empty() )
107
#if defined(_MSC_VER)
108
# pragma warning( pop )
109
#endif
110
    {
111
        auto const& t = *reinterpret_cast<T const*>(w.p_);
112
113
#if defined(__clang__)
114
# pragma clang diagnostic push
115
# pragma clang diagnostic ignored "-Wsign-compare"
116
#elif defined(__GNUC__)
117
# pragma GCC diagnostic push
118
# pragma GCC  diagnostic ignored "-Wsign-compare"
119
#elif defined(_MSC_VER)
120
# pragma warning( push )
121
# pragma warning( disable : 4018 )
122
# pragma warning( disable : 4127 )
123
#endif
124
125
        if( t < 0 )
126
        {
127
            // T is obviously signed, so this comparison is safe
128
            if( t >= (std::numeric_limits<std::int64_t>::min)() )
129
            {
130
                std::int64_t i = t;
131
                return write_int64(w, ss0, i);
132
            }
133
        }
134
        else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
135
        {
136
            std::uint64_t u = t;
137
            return write_uint64(w, ss0, u);
138
        }
139
#if defined(__clang__)
140
# pragma clang diagnostic pop
141
#elif defined(__GNUC__)
142
# pragma GCC diagnostic pop
143
#elif defined(_MSC_VER)
144
# pragma warning( pop )
145
#endif
146
147
#if defined(_MSC_VER)
148
# pragma warning( push )
149
# pragma warning( disable : 4244 )
150
#endif
151
        double d = t;
152
        return write_double(w, ss0, d);
153
#if defined(_MSC_VER)
154
# pragma warning( pop )
155
#endif
156
    }
157
158
    return resume_buffer(w, ss0);
159
}
160
161
template<class T, bool StackEmpty>
162
BOOST_FORCEINLINE
163
bool
164
write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
165
{
166
#if defined(_MSC_VER)
167
# pragma warning( push )
168
# pragma warning( disable : 4127 )
169
#endif
170
    if( StackEmpty || w.st_.empty() )
171
#if defined(_MSC_VER)
172
# pragma warning( pop )
173
#endif
174
    {
175
        double d = *reinterpret_cast<T const*>(w.p_);
176
        return write_double(w, ss0, d);
177
    }
178
179
    return resume_buffer(w, ss0);
180
}
181
182
template<class T, bool StackEmpty>
183
BOOST_FORCEINLINE
184
bool
185
write_impl(string_like_conversion_tag, writer& w, stream& ss0)
186
{
187
#if defined(_MSC_VER)
188
# pragma warning( push )
189
# pragma warning( disable : 4127 )
190
#endif
191
    if( StackEmpty || w.st_.empty() )
192
#if defined(_MSC_VER)
193
# pragma warning( pop )
194
#endif
195
    {
196
        string_view const sv = *reinterpret_cast<T const*>(w.p_);
197
        w.cs0_ = { sv.data(), sv.size() };
198
        return write_string(w, ss0);
199
    }
200
201
    return resume_string(w, ss0);
202
}
203
204
template<class T, bool StackEmpty>
205
BOOST_FORCEINLINE
206
bool
207
write_impl(sequence_conversion_tag, writer& w, stream& ss0)
208
23.2k
{
209
23.2k
    using It = iterator_type<T const>;
210
23.2k
    using Elem = value_type<T>;
211
212
23.2k
    T const* pt;
213
23.2k
    local_stream ss(ss0);
214
23.2k
    It it;
215
23.2k
    It end;
216
#if defined(_MSC_VER)
217
# pragma warning( push )
218
# pragma warning( disable : 4127 )
219
#endif
220
23.2k
    if(StackEmpty || w.st_.empty())
221
16.8k
    {
222
#if defined(_MSC_VER)
223
# pragma warning( pop )
224
#endif
225
16.8k
        BOOST_ASSERT( w.p_ );
226
16.8k
        pt = reinterpret_cast<T const*>(w.p_);
227
16.8k
        it = std::begin(*pt);
228
16.8k
        end = std::end(*pt);
229
16.8k
    }
230
6.31k
    else
231
6.31k
    {
232
6.31k
        writer::state st;
233
6.31k
        w.st_.pop(st);
234
6.31k
        w.st_.pop(it);
235
6.31k
        w.st_.pop(pt);
236
6.31k
        end = std::end(*pt);
237
6.31k
        switch(st)
238
6.31k
        {
239
0
        default:
240
19
        case writer::state::arr1: goto do_arr1;
241
6.05k
        case writer::state::arr2: goto do_arr2;
242
201
        case writer::state::arr3: goto do_arr3;
243
40
        case writer::state::arr4: goto do_arr4;
244
0
            break;
245
6.31k
        }
246
6.31k
    }
247
16.9k
do_arr1:
248
16.9k
    if(BOOST_JSON_LIKELY(ss))
249
16.8k
        ss.append('[');
250
19
    else
251
19
        return w.suspend(writer::state::arr1, it, pt);
252
16.8k
    if(it == end)
253
2.67k
        goto do_arr4;
254
14.2k
    for(;;)
255
9.53M
    {
256
9.53M
        w.p_ = std::addressof(*it);
257
9.53M
do_arr2:
258
9.53M
        if( !write_impl<Elem, StackEmpty>(w, ss) )
259
6.05k
            return w.suspend(writer::state::arr2, it, pt);
260
9.53M
        if(BOOST_JSON_UNLIKELY( ++it == end ))
261
14.2k
            break;
262
9.51M
do_arr3:
263
9.51M
        if(BOOST_JSON_LIKELY(ss))
264
9.51M
            ss.append(',');
265
201
        else
266
201
            return w.suspend(writer::state::arr3, it, pt);
267
9.51M
    }
268
16.9k
do_arr4:
269
16.9k
    if(BOOST_JSON_LIKELY(ss))
270
16.8k
        ss.append(']');
271
40
    else
272
40
        return w.suspend(writer::state::arr4, it, pt);
273
16.8k
    return true;
274
16.9k
}
bool boost::json::detail::write_impl<boost::json::array, true>(boost::json::detail::sequence_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
208
16.8k
{
209
16.8k
    using It = iterator_type<T const>;
210
16.8k
    using Elem = value_type<T>;
211
212
16.8k
    T const* pt;
213
16.8k
    local_stream ss(ss0);
214
16.8k
    It it;
215
16.8k
    It end;
216
#if defined(_MSC_VER)
217
# pragma warning( push )
218
# pragma warning( disable : 4127 )
219
#endif
220
16.8k
    if(StackEmpty || w.st_.empty())
221
16.8k
    {
222
#if defined(_MSC_VER)
223
# pragma warning( pop )
224
#endif
225
16.8k
        BOOST_ASSERT( w.p_ );
226
16.8k
        pt = reinterpret_cast<T const*>(w.p_);
227
16.8k
        it = std::begin(*pt);
228
16.8k
        end = std::end(*pt);
229
16.8k
    }
230
0
    else
231
0
    {
232
0
        writer::state st;
233
0
        w.st_.pop(st);
234
0
        w.st_.pop(it);
235
0
        w.st_.pop(pt);
236
0
        end = std::end(*pt);
237
0
        switch(st)
238
0
        {
239
0
        default:
240
0
        case writer::state::arr1: goto do_arr1;
241
0
        case writer::state::arr2: goto do_arr2;
242
0
        case writer::state::arr3: goto do_arr3;
243
0
        case writer::state::arr4: goto do_arr4;
244
0
            break;
245
0
        }
246
0
    }
247
16.8k
do_arr1:
248
16.8k
    if(BOOST_JSON_LIKELY(ss))
249
16.8k
        ss.append('[');
250
19
    else
251
19
        return w.suspend(writer::state::arr1, it, pt);
252
16.8k
    if(it == end)
253
2.66k
        goto do_arr4;
254
14.2k
    for(;;)
255
1.66M
    {
256
1.66M
        w.p_ = std::addressof(*it);
257
1.66M
do_arr2:
258
1.66M
        if( !write_impl<Elem, StackEmpty>(w, ss) )
259
2.53k
            return w.suspend(writer::state::arr2, it, pt);
260
1.66M
        if(BOOST_JSON_UNLIKELY( ++it == end ))
261
11.5k
            break;
262
1.64M
do_arr3:
263
1.64M
        if(BOOST_JSON_LIKELY(ss))
264
1.64M
            ss.append(',');
265
103
        else
266
103
            return w.suspend(writer::state::arr3, it, pt);
267
1.64M
    }
268
14.2k
do_arr4:
269
14.2k
    if(BOOST_JSON_LIKELY(ss))
270
14.1k
        ss.append(']');
271
29
    else
272
29
        return w.suspend(writer::state::arr4, it, pt);
273
14.1k
    return true;
274
14.2k
}
bool boost::json::detail::write_impl<boost::json::array, false>(boost::json::detail::sequence_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
208
6.31k
{
209
6.31k
    using It = iterator_type<T const>;
210
6.31k
    using Elem = value_type<T>;
211
212
6.31k
    T const* pt;
213
6.31k
    local_stream ss(ss0);
214
6.31k
    It it;
215
6.31k
    It end;
216
#if defined(_MSC_VER)
217
# pragma warning( push )
218
# pragma warning( disable : 4127 )
219
#endif
220
6.31k
    if(StackEmpty || w.st_.empty())
221
0
    {
222
#if defined(_MSC_VER)
223
# pragma warning( pop )
224
#endif
225
0
        BOOST_ASSERT( w.p_ );
226
0
        pt = reinterpret_cast<T const*>(w.p_);
227
0
        it = std::begin(*pt);
228
0
        end = std::end(*pt);
229
0
    }
230
6.31k
    else
231
6.31k
    {
232
6.31k
        writer::state st;
233
6.31k
        w.st_.pop(st);
234
6.31k
        w.st_.pop(it);
235
6.31k
        w.st_.pop(pt);
236
6.31k
        end = std::end(*pt);
237
6.31k
        switch(st)
238
6.31k
        {
239
0
        default:
240
19
        case writer::state::arr1: goto do_arr1;
241
6.05k
        case writer::state::arr2: goto do_arr2;
242
201
        case writer::state::arr3: goto do_arr3;
243
40
        case writer::state::arr4: goto do_arr4;
244
0
            break;
245
6.31k
        }
246
6.31k
    }
247
19
do_arr1:
248
19
    if(BOOST_JSON_LIKELY(ss))
249
19
        ss.append('[');
250
0
    else
251
0
        return w.suspend(writer::state::arr1, it, pt);
252
19
    if(it == end)
253
10
        goto do_arr4;
254
9
    for(;;)
255
7.86M
    {
256
7.86M
        w.p_ = std::addressof(*it);
257
7.87M
do_arr2:
258
7.87M
        if( !write_impl<Elem, StackEmpty>(w, ss) )
259
3.51k
            return w.suspend(writer::state::arr2, it, pt);
260
7.87M
        if(BOOST_JSON_UNLIKELY( ++it == end ))
261
2.64k
            break;
262
7.86M
do_arr3:
263
7.86M
        if(BOOST_JSON_LIKELY(ss))
264
7.86M
            ss.append(',');
265
98
        else
266
98
            return w.suspend(writer::state::arr3, it, pt);
267
7.86M
    }
268
2.69k
do_arr4:
269
2.69k
    if(BOOST_JSON_LIKELY(ss))
270
2.68k
        ss.append(']');
271
11
    else
272
11
        return w.suspend(writer::state::arr4, it, pt);
273
2.68k
    return true;
274
2.69k
}
275
276
template<class T, bool StackEmpty>
277
BOOST_FORCEINLINE
278
bool
279
write_impl(map_like_conversion_tag, writer& w, stream& ss0)
280
12.1k
{
281
12.1k
    using It = iterator_type<T const>;
282
12.1k
    using Mapped = mapped_type<T>;
283
284
12.1k
    T const* pt;
285
12.1k
    local_stream ss(ss0);
286
12.1k
    It it;
287
12.1k
    It end;
288
#if defined(_MSC_VER)
289
# pragma warning( push )
290
# pragma warning( disable : 4127 )
291
#endif
292
12.1k
    if(StackEmpty || w.st_.empty())
293
#if defined(_MSC_VER)
294
# pragma warning( pop )
295
#endif
296
10.0k
    {
297
10.0k
        BOOST_ASSERT( w.p_ );
298
10.0k
        pt = reinterpret_cast<T const*>(w.p_);
299
10.0k
        it = std::begin(*pt);
300
10.0k
        end = std::end(*pt);
301
10.0k
    }
302
2.05k
    else
303
2.05k
    {
304
2.05k
        writer::state st;
305
2.05k
        w.st_.pop(st);
306
2.05k
        w.st_.pop(it);
307
2.05k
        w.st_.pop(pt);
308
2.05k
        end = std::end(*pt);
309
2.05k
        switch(st)
310
2.05k
        {
311
0
        default:
312
22
        case writer::state::obj1: goto do_obj1;
313
377
        case writer::state::obj2: goto do_obj2;
314
22
        case writer::state::obj3: goto do_obj3;
315
1.58k
        case writer::state::obj4: goto do_obj4;
316
24
        case writer::state::obj5: goto do_obj5;
317
28
        case writer::state::obj6: goto do_obj6;
318
0
            break;
319
2.05k
        }
320
2.05k
    }
321
10.1k
do_obj1:
322
10.1k
    if(BOOST_JSON_LIKELY( ss ))
323
10.0k
        ss.append('{');
324
22
    else
325
22
        return w.suspend(writer::state::obj1, it, pt);
326
10.0k
    if(BOOST_JSON_UNLIKELY( it == end ))
327
5.64k
        goto do_obj6;
328
4.43k
    for(;;)
329
14.7k
    {
330
14.7k
        {
331
14.7k
            using std::get;
332
14.7k
            string_view const sv = get<0>(*it);
333
14.7k
            w.cs0_ = { sv.data(), sv.size() };
334
14.7k
        }
335
14.7k
        if( true )
336
14.7k
        {
337
14.7k
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338
220
                return w.suspend(writer::state::obj2, it, pt);
339
14.7k
        }
340
0
        else
341
0
        {
342
377
do_obj2:
343
377
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344
157
                return w.suspend(writer::state::obj2, it, pt);
345
377
        }
346
14.7k
do_obj3:
347
14.7k
        if(BOOST_JSON_LIKELY(ss))
348
14.7k
            ss.append(':');
349
22
        else
350
22
            return w.suspend(writer::state::obj3, it, pt);
351
16.3k
do_obj4:
352
16.3k
        {
353
16.3k
            using std::get;
354
16.3k
            w.p_ = std::addressof( get<1>(*it) );
355
16.3k
        }
356
16.3k
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357
1.58k
            return w.suspend(writer::state::obj4, it, pt);
358
14.7k
        ++it;
359
14.7k
        if(BOOST_JSON_UNLIKELY(it == end))
360
4.43k
            break;
361
10.3k
do_obj5:
362
10.3k
        if(BOOST_JSON_LIKELY(ss))
363
10.3k
            ss.append(',');
364
24
        else
365
24
            return w.suspend(writer::state::obj5, it, pt);
366
10.3k
    }
367
10.1k
do_obj6:
368
10.1k
    if(BOOST_JSON_LIKELY( ss ))
369
10.0k
    {
370
10.0k
        ss.append('}');
371
10.0k
        return true;
372
10.0k
    }
373
28
    return w.suspend(writer::state::obj6, it, pt);
374
10.1k
}
bool boost::json::detail::write_impl<boost::json::object, true>(boost::json::detail::map_like_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
280
10.0k
{
281
10.0k
    using It = iterator_type<T const>;
282
10.0k
    using Mapped = mapped_type<T>;
283
284
10.0k
    T const* pt;
285
10.0k
    local_stream ss(ss0);
286
10.0k
    It it;
287
10.0k
    It end;
288
#if defined(_MSC_VER)
289
# pragma warning( push )
290
# pragma warning( disable : 4127 )
291
#endif
292
10.0k
    if(StackEmpty || w.st_.empty())
293
#if defined(_MSC_VER)
294
# pragma warning( pop )
295
#endif
296
10.0k
    {
297
10.0k
        BOOST_ASSERT( w.p_ );
298
10.0k
        pt = reinterpret_cast<T const*>(w.p_);
299
10.0k
        it = std::begin(*pt);
300
10.0k
        end = std::end(*pt);
301
10.0k
    }
302
0
    else
303
0
    {
304
0
        writer::state st;
305
0
        w.st_.pop(st);
306
0
        w.st_.pop(it);
307
0
        w.st_.pop(pt);
308
0
        end = std::end(*pt);
309
0
        switch(st)
310
0
        {
311
0
        default:
312
0
        case writer::state::obj1: goto do_obj1;
313
0
        case writer::state::obj2: goto do_obj2;
314
0
        case writer::state::obj3: goto do_obj3;
315
0
        case writer::state::obj4: goto do_obj4;
316
0
        case writer::state::obj5: goto do_obj5;
317
0
        case writer::state::obj6: goto do_obj6;
318
0
            break;
319
0
        }
320
0
    }
321
10.0k
do_obj1:
322
10.0k
    if(BOOST_JSON_LIKELY( ss ))
323
10.0k
        ss.append('{');
324
22
    else
325
22
        return w.suspend(writer::state::obj1, it, pt);
326
10.0k
    if(BOOST_JSON_UNLIKELY( it == end ))
327
5.63k
        goto do_obj6;
328
4.42k
    for(;;)
329
12.5k
    {
330
12.5k
        {
331
12.5k
            using std::get;
332
12.5k
            string_view const sv = get<0>(*it);
333
12.5k
            w.cs0_ = { sv.data(), sv.size() };
334
12.5k
        }
335
12.5k
        if( true )
336
12.5k
        {
337
12.5k
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338
159
                return w.suspend(writer::state::obj2, it, pt);
339
12.5k
        }
340
0
        else
341
0
        {
342
0
do_obj2:
343
0
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344
0
                return w.suspend(writer::state::obj2, it, pt);
345
0
        }
346
12.4k
do_obj3:
347
12.4k
        if(BOOST_JSON_LIKELY(ss))
348
12.4k
            ss.append(':');
349
11
        else
350
11
            return w.suspend(writer::state::obj3, it, pt);
351
12.4k
do_obj4:
352
12.4k
        {
353
12.4k
            using std::get;
354
12.4k
            w.p_ = std::addressof( get<1>(*it) );
355
12.4k
        }
356
12.4k
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357
962
            return w.suspend(writer::state::obj4, it, pt);
358
11.4k
        ++it;
359
11.4k
        if(BOOST_JSON_UNLIKELY(it == end))
360
3.28k
            break;
361
8.17k
do_obj5:
362
8.17k
        if(BOOST_JSON_LIKELY(ss))
363
8.16k
            ss.append(',');
364
11
        else
365
11
            return w.suspend(writer::state::obj5, it, pt);
366
8.17k
    }
367
8.91k
do_obj6:
368
8.91k
    if(BOOST_JSON_LIKELY( ss ))
369
8.89k
    {
370
8.89k
        ss.append('}');
371
8.89k
        return true;
372
8.89k
    }
373
18
    return w.suspend(writer::state::obj6, it, pt);
374
8.91k
}
bool boost::json::detail::write_impl<boost::json::object, false>(boost::json::detail::map_like_conversion_tag, boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
280
2.05k
{
281
2.05k
    using It = iterator_type<T const>;
282
2.05k
    using Mapped = mapped_type<T>;
283
284
2.05k
    T const* pt;
285
2.05k
    local_stream ss(ss0);
286
2.05k
    It it;
287
2.05k
    It end;
288
#if defined(_MSC_VER)
289
# pragma warning( push )
290
# pragma warning( disable : 4127 )
291
#endif
292
2.05k
    if(StackEmpty || w.st_.empty())
293
#if defined(_MSC_VER)
294
# pragma warning( pop )
295
#endif
296
0
    {
297
0
        BOOST_ASSERT( w.p_ );
298
0
        pt = reinterpret_cast<T const*>(w.p_);
299
0
        it = std::begin(*pt);
300
0
        end = std::end(*pt);
301
0
    }
302
2.05k
    else
303
2.05k
    {
304
2.05k
        writer::state st;
305
2.05k
        w.st_.pop(st);
306
2.05k
        w.st_.pop(it);
307
2.05k
        w.st_.pop(pt);
308
2.05k
        end = std::end(*pt);
309
2.05k
        switch(st)
310
2.05k
        {
311
0
        default:
312
22
        case writer::state::obj1: goto do_obj1;
313
377
        case writer::state::obj2: goto do_obj2;
314
22
        case writer::state::obj3: goto do_obj3;
315
1.58k
        case writer::state::obj4: goto do_obj4;
316
24
        case writer::state::obj5: goto do_obj5;
317
28
        case writer::state::obj6: goto do_obj6;
318
0
            break;
319
2.05k
        }
320
2.05k
    }
321
22
do_obj1:
322
22
    if(BOOST_JSON_LIKELY( ss ))
323
22
        ss.append('{');
324
0
    else
325
0
        return w.suspend(writer::state::obj1, it, pt);
326
22
    if(BOOST_JSON_UNLIKELY( it == end ))
327
12
        goto do_obj6;
328
10
    for(;;)
329
2.17k
    {
330
2.17k
        {
331
2.17k
            using std::get;
332
2.17k
            string_view const sv = get<0>(*it);
333
2.17k
            w.cs0_ = { sv.data(), sv.size() };
334
2.17k
        }
335
2.17k
        if( true )
336
2.17k
        {
337
2.17k
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
338
61
                return w.suspend(writer::state::obj2, it, pt);
339
2.17k
        }
340
0
        else
341
0
        {
342
377
do_obj2:
343
377
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
344
157
                return w.suspend(writer::state::obj2, it, pt);
345
377
        }
346
2.35k
do_obj3:
347
2.35k
        if(BOOST_JSON_LIKELY(ss))
348
2.34k
            ss.append(':');
349
11
        else
350
11
            return w.suspend(writer::state::obj3, it, pt);
351
3.92k
do_obj4:
352
3.92k
        {
353
3.92k
            using std::get;
354
3.92k
            w.p_ = std::addressof( get<1>(*it) );
355
3.92k
        }
356
3.92k
        if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
357
621
            return w.suspend(writer::state::obj4, it, pt);
358
3.30k
        ++it;
359
3.30k
        if(BOOST_JSON_UNLIKELY(it == end))
360
1.15k
            break;
361
2.17k
do_obj5:
362
2.17k
        if(BOOST_JSON_LIKELY(ss))
363
2.16k
            ss.append(',');
364
13
        else
365
13
            return w.suspend(writer::state::obj5, it, pt);
366
2.17k
    }
367
1.19k
do_obj6:
368
1.19k
    if(BOOST_JSON_LIKELY( ss ))
369
1.18k
    {
370
1.18k
        ss.append('}');
371
1.18k
        return true;
372
1.18k
    }
373
10
    return w.suspend(writer::state::obj6, it, pt);
374
1.19k
}
375
376
template< class T, bool StackEmpty >
377
struct serialize_tuple_elem_helper
378
{
379
    writer& w;
380
    stream& ss;
381
    T const* pt;
382
383
    template< std::size_t I >
384
    bool
385
    operator()( std::integral_constant<std::size_t, I> ) const
386
    {
387
        using std::get;
388
        w.p_ = std::addressof( get<I>(*pt) );
389
390
        using Elem = tuple_element_t<I, T>;
391
        return write_impl<Elem, StackEmpty>(w, ss);
392
    }
393
};
394
395
template<class T, bool StackEmpty>
396
BOOST_FORCEINLINE
397
bool
398
write_impl(tuple_conversion_tag, writer& w, stream& ss0)
399
{
400
    T const* pt;
401
    local_stream ss(ss0);
402
    std::size_t cur;
403
    constexpr std::size_t N = std::tuple_size<T>::value;
404
#if defined(_MSC_VER)
405
# pragma warning( push )
406
# pragma warning( disable : 4127 )
407
#endif
408
    if(StackEmpty || w.st_.empty())
409
    {
410
#if defined(_MSC_VER)
411
# pragma warning( pop )
412
#endif
413
        BOOST_ASSERT( w.p_ );
414
        pt = reinterpret_cast<T const*>(w.p_);
415
        cur = 0;
416
    }
417
    else
418
    {
419
        writer::state st;
420
        w.st_.pop(st);
421
        w.st_.pop(cur);
422
        w.st_.pop(pt);
423
        switch(st)
424
        {
425
        default:
426
        case writer::state::arr1: goto do_arr1;
427
        case writer::state::arr2: goto do_arr2;
428
        case writer::state::arr3: goto do_arr3;
429
        case writer::state::arr4: goto do_arr4;
430
            break;
431
        }
432
    }
433
do_arr1:
434
    if(BOOST_JSON_LIKELY(ss))
435
        ss.append('[');
436
    else
437
        return w.suspend(writer::state::arr1, cur, pt);
438
    for(;;)
439
    {
440
do_arr2:
441
        {
442
            bool const stop = !mp11::mp_with_index<N>(
443
                cur,
444
                serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
445
            if(BOOST_JSON_UNLIKELY( stop ))
446
                return w.suspend(writer::state::arr2, cur, pt);
447
        }
448
        if(BOOST_JSON_UNLIKELY( ++cur == N ))
449
            break;
450
do_arr3:
451
        if(BOOST_JSON_LIKELY(ss))
452
            ss.append(',');
453
        else
454
            return w.suspend(writer::state::arr3, cur, pt);
455
    }
456
do_arr4:
457
    if(BOOST_JSON_LIKELY(ss))
458
        ss.append(']');
459
    else
460
        return w.suspend(writer::state::arr4, cur, pt);
461
    return true;
462
}
463
464
template< class T, bool StackEmpty >
465
struct serialize_struct_elem_helper
466
{
467
    static_assert(
468
        uniquely_named_members<T>::value,
469
        "The type has several described members with the same name.");
470
471
    writer& w;
472
    local_stream& ss;
473
    T const* pt;
474
    writer::state st;
475
476
    template< std::size_t I >
477
    writer::state
478
    operator()( std::integral_constant<std::size_t, I> ) const
479
    {
480
        using Ds = described_members<T>;
481
        using D = mp11::mp_at_c<Ds, I>;
482
        using M = described_member_t<T, D>;
483
484
        switch(st)
485
        {
486
        case writer::state::obj2: goto do_obj2;
487
        case writer::state::obj3: goto do_obj3;
488
        case writer::state::obj4: goto do_obj4;
489
        default: break;
490
        }
491
492
        {
493
            string_view const sv = D::name;
494
            w.cs0_ = { sv.data(), sv.size() };
495
        }
496
        if( true )
497
        {
498
            if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
499
                return writer::state::obj2;
500
        }
501
        else
502
        {
503
do_obj2:
504
            if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
505
                return writer::state::obj2;
506
        }
507
do_obj3:
508
        if(BOOST_JSON_LIKELY(ss))
509
            ss.append(':');
510
        else
511
            return writer::state::obj3;
512
do_obj4:
513
        w.p_ = std::addressof( pt->* D::pointer );
514
        if(BOOST_JSON_UNLIKELY((
515
                !write_impl<M, StackEmpty>(w, ss) )))
516
            return writer::state::obj4;
517
518
        return writer::state{};
519
    }
520
};
521
522
template<class T, bool StackEmpty>
523
BOOST_FORCEINLINE
524
bool
525
write_impl(described_class_conversion_tag, writer& w, stream& ss0)
526
{
527
    using Ds = described_members<T>;
528
529
    T const* pt;
530
    local_stream ss(ss0);
531
    std::size_t cur;
532
    constexpr std::size_t N = mp11::mp_size<Ds>::value;
533
    writer::state st;
534
#if defined(_MSC_VER)
535
# pragma warning( push )
536
# pragma warning( disable : 4127 )
537
#endif
538
    if(StackEmpty || w.st_.empty())
539
#if defined(_MSC_VER)
540
# pragma warning( pop )
541
#endif
542
    {
543
        BOOST_ASSERT( w.p_ );
544
        pt = reinterpret_cast<T const*>(w.p_);
545
        cur = 0;
546
    }
547
    else
548
    {
549
        w.st_.pop(st);
550
        w.st_.pop(cur);
551
        w.st_.pop(pt);
552
        switch(st)
553
        {
554
        default:
555
        case writer::state::obj1: goto do_obj1;
556
        case writer::state::obj2: // fall through
557
        case writer::state::obj3: // fall through
558
        case writer::state::obj4: goto do_obj2;
559
        case writer::state::obj5: goto do_obj5;
560
        case writer::state::obj6: goto do_obj6;
561
            break;
562
        }
563
    }
564
do_obj1:
565
    if(BOOST_JSON_LIKELY( ss ))
566
        ss.append('{');
567
    else
568
        return w.suspend(writer::state::obj1, cur, pt);
569
    if(BOOST_JSON_UNLIKELY( cur == N ))
570
        goto do_obj6;
571
    for(;;)
572
    {
573
        st = {};
574
do_obj2:
575
        st = mp11::mp_with_index<N>(
576
            cur,
577
            serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
578
        if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
579
            return w.suspend(st, cur, pt);
580
        ++cur;
581
        if(BOOST_JSON_UNLIKELY(cur == N))
582
            break;
583
do_obj5:
584
        if(BOOST_JSON_LIKELY(ss))
585
            ss.append(',');
586
        else
587
            return w.suspend(writer::state::obj5, cur, pt);
588
    }
589
do_obj6:
590
    if(BOOST_JSON_LIKELY( ss ))
591
    {
592
        ss.append('}');
593
        return true;
594
    }
595
    return w.suspend(writer::state::obj6, cur, pt);
596
}
597
598
template<class T, bool StackEmpty>
599
BOOST_FORCEINLINE
600
bool
601
write_impl(described_enum_conversion_tag, writer& w, stream& ss)
602
{
603
#ifdef BOOST_DESCRIBE_CXX14
604
    using Integer = typename std::underlying_type<T>::type;
605
606
#if defined(_MSC_VER)
607
# pragma warning( push )
608
# pragma warning( disable : 4127 )
609
#endif
610
    if(StackEmpty || w.st_.empty())
611
#if defined(_MSC_VER)
612
# pragma warning( pop )
613
#endif
614
    {
615
        BOOST_ASSERT( w.p_ );
616
        T const* pt = reinterpret_cast<T const*>(w.p_);
617
        char const* const name = describe::enum_to_string(*pt, nullptr);
618
        if( name )
619
        {
620
            string_view const sv = name;
621
            w.cs0_ = { sv.data(), sv.size() };
622
            return write_string(w, ss);
623
        }
624
        else
625
        {
626
            Integer n = static_cast<Integer>(*pt);
627
            w.p_ = &n;
628
            return write_impl<Integer, true>(w, ss);
629
        }
630
    }
631
    else
632
    {
633
        writer::state st;
634
        w.st_.peek(st);
635
        if( st == writer::state::lit )
636
            return write_impl<Integer, false>(w, ss);
637
        else
638
            return resume_string(w, ss);
639
    }
640
#else // BOOST_DESCRIBE_CXX14
641
    (void)w;
642
    (void)ss;
643
    static_assert(
644
        !std::is_same<T, T>::value,
645
        "described enums require C++14 support");
646
    return false;
647
#endif // BOOST_DESCRIBE_CXX14
648
}
649
650
template< class T, bool StackEmpty >
651
struct serialize_variant_elem_helper
652
{
653
    writer& w;
654
    stream& ss;
655
656
    template<class Elem>
657
    bool
658
    operator()(Elem const& x) const
659
    {
660
        w.p_ = std::addressof(x);
661
        return write_impl<Elem, true>(w, ss);
662
    }
663
};
664
665
template< class T >
666
struct serialize_variant_elem_helper<T, false>
667
{
668
    writer& w;
669
    stream& ss;
670
671
    template< std::size_t I >
672
    bool
673
    operator()( std::integral_constant<std::size_t, I> ) const
674
    {
675
        using std::get;
676
        using Elem = remove_cvref<decltype(get<I>(
677
            std::declval<T const&>() ))>;
678
        return write_impl<Elem, false>(w, ss);
679
    }
680
};
681
682
template<class T, bool StackEmpty>
683
BOOST_FORCEINLINE
684
bool
685
write_impl(variant_conversion_tag, writer& w, stream& ss)
686
{
687
    T const* pt;
688
689
    using Index = remove_cvref<decltype( pt->index() )>;
690
691
#if defined(_MSC_VER)
692
# pragma warning( push )
693
# pragma warning( disable : 4127 )
694
#endif
695
    if(StackEmpty || w.st_.empty())
696
#if defined(_MSC_VER)
697
# pragma warning( pop )
698
#endif
699
    {
700
        BOOST_ASSERT( w.p_ );
701
        pt = reinterpret_cast<T const*>(w.p_);
702
        if(BOOST_JSON_LIKELY((
703
                visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
704
            return true;
705
706
        Index const ix = pt->index();
707
        w.st_.push(ix);
708
        return false;
709
    }
710
    else
711
    {
712
        Index ix;
713
        w.st_.pop(ix);
714
715
        constexpr std::size_t N = mp11::mp_size<T>::value;
716
        if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
717
                ix,
718
                serialize_variant_elem_helper<T, false>{w, ss}))))
719
            return true;
720
721
        w.st_.push(ix);
722
        return false;
723
    }
724
}
725
726
template<class T, bool StackEmpty>
727
BOOST_FORCEINLINE
728
bool
729
write_impl(optional_conversion_tag, writer& w, stream& ss)
730
{
731
    using Elem = value_result_type<T>;
732
733
    bool done;
734
    bool has_value;
735
736
#if defined(_MSC_VER)
737
# pragma warning( push )
738
# pragma warning( disable : 4127 )
739
#endif
740
    if(StackEmpty || w.st_.empty())
741
#if defined(_MSC_VER)
742
# pragma warning( pop )
743
#endif
744
    {
745
        BOOST_ASSERT( w.p_ );
746
        T const* pt = reinterpret_cast<T const*>(w.p_);
747
        has_value = static_cast<bool>(*pt);
748
        if( has_value )
749
        {
750
            w.p_ = std::addressof( *(*pt) );
751
            done = write_impl<Elem, true>(w, ss);
752
        }
753
        else
754
        {
755
            w.p_ = nullptr;
756
            done = write_impl<std::nullptr_t, true>(w, ss);;
757
        }
758
    }
759
    else
760
    {
761
        w.st_.pop(has_value);
762
763
        if( has_value )
764
            done = write_impl<Elem, false>(w, ss);
765
        else
766
            done = write_impl<std::nullptr_t, false>(w, ss);
767
    }
768
769
    if(BOOST_JSON_UNLIKELY( !done ))
770
        w.st_.push(has_value);
771
772
    return done;
773
}
774
775
template<class T, bool StackEmpty>
776
BOOST_FORCEINLINE
777
bool
778
write_impl(path_conversion_tag, writer& w, stream& ss)
779
{
780
#if defined(_MSC_VER)
781
# pragma warning( push )
782
# pragma warning( disable : 4127 )
783
#endif
784
    if(StackEmpty || w.st_.empty())
785
#if defined(_MSC_VER)
786
# pragma warning( pop )
787
#endif
788
    {
789
        BOOST_ASSERT( w.p_ );
790
        T const* pt = reinterpret_cast<T const*>(w.p_);
791
792
        std::string const s = pt->generic_string();
793
        w.cs0_ = { s.data(), s.size() };
794
        if(BOOST_JSON_LIKELY( write_string(w, ss) ))
795
            return true;
796
797
        std::size_t const used = w.cs0_.used( s.data() );
798
        w.st_.push( used );
799
        w.st_.push( std::move(s) );
800
        return false;
801
    }
802
    else
803
    {
804
        std::string s;
805
        std::size_t used;
806
        w.st_.pop( s );
807
        w.st_.pop( used );
808
809
        w.cs0_ = { s.data(), s.size() };
810
        w.cs0_.skip(used);
811
812
        if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
813
            return true;
814
815
        used = w.cs0_.used( s.data() );
816
        w.st_.push( used );
817
        w.st_.push( std::move(s) );
818
        return false;
819
    }
820
}
821
822
template<class T, bool StackEmpty>
823
bool
824
write_impl(writer& w, stream& ss)
825
9.55M
{
826
9.55M
    using cat = detail::generic_conversion_category<T>;
827
9.55M
    return write_impl<T, StackEmpty>( cat(), w, ss );
828
9.55M
}
bool boost::json::detail::write_impl<boost::json::value, true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
825
1.66M
{
826
1.66M
    using cat = detail::generic_conversion_category<T>;
827
1.66M
    return write_impl<T, StackEmpty>( cat(), w, ss );
828
1.66M
}
bool boost::json::detail::write_impl<boost::json::value, false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
825
7.87M
{
826
7.87M
    using cat = detail::generic_conversion_category<T>;
827
7.87M
    return write_impl<T, StackEmpty>( cat(), w, ss );
828
7.87M
}
bool boost::json::detail::write_impl<boost::json::value&, true>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
825
12.4k
{
826
12.4k
    using cat = detail::generic_conversion_category<T>;
827
12.4k
    return write_impl<T, StackEmpty>( cat(), w, ss );
828
12.4k
}
bool boost::json::detail::write_impl<boost::json::value&, false>(boost::json::detail::writer&, boost::json::detail::stream&)
Line
Count
Source
825
3.92k
{
826
3.92k
    using cat = detail::generic_conversion_category<T>;
827
3.92k
    return write_impl<T, StackEmpty>( cat(), w, ss );
828
3.92k
}
Unexecuted instantiation: bool boost::json::detail::write_impl<decltype(nullptr), true>(boost::json::detail::writer&, boost::json::detail::stream&)
Unexecuted instantiation: bool boost::json::detail::write_impl<decltype(nullptr), false>(boost::json::detail::writer&, boost::json::detail::stream&)
829
830
} // namespace detail
831
832
template<class T>
833
void
834
serializer::reset(T const* p) noexcept
835
{
836
    BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
837
    BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
838
839
    p_ = p;
840
    fn0_ = &detail::write_impl<T, true>;
841
    fn1_ = &detail::write_impl<T, false>;
842
    st_.clear();
843
    done_ = false;
844
}
845
846
} // namespace json
847
} // namespace boost
848
849
#endif // BOOST_JSON_IMPL_SERIALIZER_HPP