Coverage Report

Created: 2024-02-11 06:17

/src/boost/boost/json/basic_parser_impl.hpp
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4
//
5
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
//
8
// Official repository: https://github.com/boostorg/json
9
//
10
11
#ifndef BOOST_JSON_BASIC_PARSER_IMPL_HPP
12
#define BOOST_JSON_BASIC_PARSER_IMPL_HPP
13
14
#include <boost/json/detail/config.hpp>
15
#include <boost/json/basic_parser.hpp>
16
#include <boost/json/error.hpp>
17
#include <boost/json/detail/buffer.hpp>
18
#include <boost/json/detail/charconv/from_chars.hpp>
19
#include <boost/json/detail/sse2.hpp>
20
#include <boost/mp11/algorithm.hpp>
21
#include <boost/mp11/integral.hpp>
22
#include <cmath>
23
#include <limits>
24
#include <cstring>
25
26
#ifdef _MSC_VER
27
#pragma warning(push)
28
#pragma warning(disable: 4702) // unreachable code
29
#pragma warning(disable: 4127) // conditional expression is constant
30
#endif
31
32
/*  This file must be manually included to get the
33
    function template definitions for basic_parser.
34
*/
35
36
/*  Reference:
37
38
    https://www.json.org/
39
40
    RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
41
    https://tools.ietf.org/html/rfc7159
42
43
    https://ampl.com/netlib/fp/dtoa.c
44
*/
45
46
#ifndef BOOST_JSON_DOCS
47
48
namespace boost {
49
namespace json {
50
namespace detail {
51
52
inline
53
double
54
pow10(int exp) noexcept
55
5.55M
{
56
5.55M
    static double const tab[618] = {
57
5.55M
                        1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
58
59
5.55M
        1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
60
5.55M
        1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
61
5.55M
        1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
62
5.55M
        1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
63
5.55M
        1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
64
5.55M
        1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
65
5.55M
        1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
66
5.55M
        1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
67
5.55M
        1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
68
5.55M
        1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
69
70
5.55M
        1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
71
5.55M
        1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
72
5.55M
        1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
73
5.55M
        1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
74
5.55M
        1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
75
5.55M
        1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
76
5.55M
        1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
77
5.55M
        1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
78
5.55M
        1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
79
5.55M
        1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
80
81
5.55M
        1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
82
5.55M
        1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
83
5.55M
        1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
84
5.55M
        1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
85
5.55M
        1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
86
5.55M
        1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
87
5.55M
        1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
88
5.55M
        1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
89
5.55M
        1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
90
5.55M
        1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
91
92
5.55M
        1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
93
5.55M
        1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
94
5.55M
        1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
95
5.55M
        1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
96
5.55M
        1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
97
5.55M
        1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
98
5.55M
        1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
99
5.55M
        1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
100
5.55M
        1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
101
5.55M
        1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
102
103
5.55M
        1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
104
5.55M
        1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
105
5.55M
        1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
106
5.55M
        1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
107
5.55M
        1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
108
5.55M
        1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
109
5.55M
        1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
110
5.55M
        1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
111
5.55M
        1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
112
5.55M
        1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
113
114
5.55M
        1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
115
5.55M
        1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
116
5.55M
        1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
117
5.55M
        1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
118
5.55M
        1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
119
5.55M
        1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
120
5.55M
        1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
121
5.55M
        1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
122
5.55M
        1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
123
5.55M
        1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
124
125
5.55M
        1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
126
127
5.55M
    if( exp > 308 )
128
42.6k
    {
129
42.6k
        return std::numeric_limits<double>::infinity();
130
42.6k
    }
131
5.51M
    else if( exp < -308 )
132
9.07k
    {
133
        // due to the way pow10 is used by dec_to_float,
134
        // we can afford to return 0.0 here
135
9.07k
        return 0.0;
136
9.07k
    }
137
5.50M
    else
138
5.50M
    {
139
5.50M
        exp += 308;
140
5.50M
        BOOST_ASSERT(exp >= 0 && exp < 618);
141
5.50M
        return tab[exp];
142
5.50M
    }
143
5.55M
}
144
145
inline
146
double
147
dec_to_float(
148
    std::uint64_t m,
149
    std::int32_t e,
150
    bool neg) noexcept
151
5.57M
{
152
    // convert to double explicitly to silence warnings
153
5.57M
    double x = static_cast<double>(m);
154
5.57M
    if(neg)
155
30.2k
        x = -x;
156
157
5.57M
    if(e < -305)
158
11.0k
    {
159
11.0k
        x *= 1e-305 ;
160
11.0k
        e += 305;
161
11.0k
    }
162
163
5.57M
    if(e >= -22 && e < 0)
164
43.3k
        return x / pow10(-e);
165
166
5.52M
    return x * pow10(e);
167
5.57M
}
168
169
inline
170
bool
171
is_control(char c) noexcept
172
57.3M
{
173
57.3M
    return static_cast<unsigned char>(c) < 32;
174
57.3M
}
175
176
inline
177
int
178
hex_digit(unsigned char c) noexcept
179
12.5M
{
180
    // by Peter Dimov
181
12.5M
    if( c >= '0' && c <= '9' )
182
6.98M
        return c - '0';
183
5.53M
    c &= ~0x20;
184
5.53M
    if( c >= 'A' && c <= 'F' )
185
5.52M
        return 10 + c - 'A';
186
1.28k
    return -1;
187
5.53M
}
188
189
enum json_literal
190
{
191
    null_literal = 0,
192
    true_literal,
193
    false_literal,
194
    infinity_literal,
195
    neg_infinity_literal,
196
    nan_literal,
197
    resume_literal = -1
198
};
199
200
} // detail
201
202
//----------------------------------------------------------
203
204
template< class Handler >
205
template< bool StackEmpty_, char First_ >
206
struct basic_parser<Handler>::
207
parse_number_helper
208
{
209
    basic_parser* parser;
210
    char const* p;
211
212
    template< std::size_t N >
213
    char const*
214
    operator()( mp11::mp_size_t<N> ) const
215
10.6M
    {
216
10.6M
        return parser->parse_number(
217
10.6M
            p,
218
10.6M
            std::integral_constant<bool, StackEmpty_>(),
219
10.6M
            std::integral_constant<char, First_>(),
220
10.6M
            std::integral_constant<
221
10.6M
                number_precision, static_cast<number_precision>(N)>() );
222
10.6M
    }
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)48>::operator()<0ul>(std::__1::integral_constant<unsigned long, 0ul>) const
Line
Count
Source
215
228k
    {
216
228k
        return parser->parse_number(
217
228k
            p,
218
228k
            std::integral_constant<bool, StackEmpty_>(),
219
228k
            std::integral_constant<char, First_>(),
220
228k
            std::integral_constant<
221
228k
                number_precision, static_cast<number_precision>(N)>() );
222
228k
    }
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)48>::operator()<1ul>(std::__1::integral_constant<unsigned long, 1ul>) const
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)48>::operator()<2ul>(std::__1::integral_constant<unsigned long, 2ul>) const
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)45>::operator()<0ul>(std::__1::integral_constant<unsigned long, 0ul>) const
Line
Count
Source
215
37.1k
    {
216
37.1k
        return parser->parse_number(
217
37.1k
            p,
218
37.1k
            std::integral_constant<bool, StackEmpty_>(),
219
37.1k
            std::integral_constant<char, First_>(),
220
37.1k
            std::integral_constant<
221
37.1k
                number_precision, static_cast<number_precision>(N)>() );
222
37.1k
    }
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)45>::operator()<1ul>(std::__1::integral_constant<unsigned long, 1ul>) const
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)45>::operator()<2ul>(std::__1::integral_constant<unsigned long, 2ul>) const
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)43>::operator()<0ul>(std::__1::integral_constant<unsigned long, 0ul>) const
Line
Count
Source
215
10.3M
    {
216
10.3M
        return parser->parse_number(
217
10.3M
            p,
218
10.3M
            std::integral_constant<bool, StackEmpty_>(),
219
10.3M
            std::integral_constant<char, First_>(),
220
10.3M
            std::integral_constant<
221
10.3M
                number_precision, static_cast<number_precision>(N)>() );
222
10.3M
    }
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)43>::operator()<1ul>(std::__1::integral_constant<unsigned long, 1ul>) const
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<true, (char)43>::operator()<2ul>(std::__1::integral_constant<unsigned long, 2ul>) const
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<false, (char)0>::operator()<0ul>(std::__1::integral_constant<unsigned long, 0ul>) const
Line
Count
Source
215
3.18k
    {
216
3.18k
        return parser->parse_number(
217
3.18k
            p,
218
3.18k
            std::integral_constant<bool, StackEmpty_>(),
219
3.18k
            std::integral_constant<char, First_>(),
220
3.18k
            std::integral_constant<
221
3.18k
                number_precision, static_cast<number_precision>(N)>() );
222
3.18k
    }
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<false, (char)0>::operator()<1ul>(std::__1::integral_constant<unsigned long, 1ul>) const
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_number_helper<false, (char)0>::operator()<2ul>(std::__1::integral_constant<unsigned long, 2ul>) const
223
};
224
225
//----------------------------------------------------------
226
227
template<class Handler>
228
void
229
basic_parser<Handler>::
230
reserve()
231
9.51k
{
232
9.51k
    if(BOOST_JSON_LIKELY(
233
9.51k
        ! st_.empty()))
234
2.25k
        return;
235
    // Reserve the largest stack we need,
236
    // to avoid reallocation during suspend.
237
7.26k
    st_.reserve(
238
7.26k
        sizeof(state) + // document parsing state
239
7.26k
        (sizeof(state) +
240
7.26k
            sizeof(std::size_t)) * depth() + // array and object state + size
241
7.26k
        sizeof(state) + // value parsing state
242
7.26k
        sizeof(std::size_t) + // string size
243
7.26k
        sizeof(state)); // comment state
244
7.26k
}
245
246
//----------------------------------------------------------
247
//
248
// The sentinel value is returned by parse functions
249
// to indicate that the parser failed, or suspended.
250
// this is used as it is distinct from all valid values
251
// for data in write
252
253
template<class Handler>
254
const char*
255
basic_parser<Handler>::
256
sentinel()
257
11.9M
{
258
    // the "+1" ensures that the returned pointer is unique even if
259
    // the given input buffer borders on this object
260
11.9M
    return reinterpret_cast<
261
11.9M
        const char*>(this) + 1;
262
11.9M
}
263
264
template<class Handler>
265
bool
266
basic_parser<Handler>::
267
incomplete(
268
    const detail::const_stream_wrapper& cs)
269
11.8M
{
270
11.8M
    return cs.begin() == sentinel();
271
11.8M
}
272
273
//----------------------------------------------------------
274
//
275
// These functions are declared with the BOOST_NOINLINE
276
// attribute to avoid polluting the parsers hot-path.
277
// They return the canary value to indicate suspension
278
// or failure.
279
280
template<class Handler>
281
const char*
282
basic_parser<Handler>::
283
suspend_or_fail(state st)
284
{
285
    if(BOOST_JSON_LIKELY(
286
        ! ec_ && more_))
287
    {
288
        // suspend
289
        reserve();
290
        st_.push_unchecked(st);
291
    }
292
    return sentinel();
293
}
294
295
template<class Handler>
296
const char*
297
basic_parser<Handler>::
298
suspend_or_fail(
299
    state st,
300
    std::size_t n)
301
8.01k
{
302
8.01k
    if(BOOST_JSON_LIKELY(
303
8.01k
        ! ec_ && more_))
304
2.19k
    {
305
        // suspend
306
2.19k
        reserve();
307
2.19k
        st_.push_unchecked(n);
308
2.19k
        st_.push_unchecked(st);
309
2.19k
    }
310
8.01k
    return sentinel();
311
8.01k
}
312
313
314
template<class Handler>
315
const char*
316
basic_parser<Handler>::
317
fail(const char* p) noexcept
318
0
{
319
0
    BOOST_ASSERT( p != sentinel() );
320
0
    end_ = p;
321
0
    return sentinel();
322
0
}
323
324
template<class Handler>
325
const char*
326
basic_parser<Handler>::
327
fail(
328
    const char* p,
329
    error ev,
330
    source_location const* loc) noexcept
331
4.79k
{
332
4.79k
    BOOST_ASSERT( p != sentinel() );
333
4.79k
    end_ = p;
334
4.79k
    ec_.assign(ev, loc);
335
4.79k
    return sentinel();
336
4.79k
}
337
338
template<class Handler>
339
const char*
340
basic_parser<Handler>::
341
maybe_suspend(
342
    const char* p,
343
    state st)
344
701
{
345
701
    if( p != sentinel() )
346
575
        end_ = p;
347
701
    if(BOOST_JSON_LIKELY(more_))
348
327
    {
349
        // suspend
350
327
        reserve();
351
327
        st_.push_unchecked(st);
352
327
    }
353
701
    return sentinel();
354
701
}
355
356
template<class Handler>
357
const char*
358
basic_parser<Handler>::
359
maybe_suspend(
360
    const char* p,
361
    state st,
362
    std::size_t n)
363
5.83k
{
364
5.83k
    BOOST_ASSERT( p != sentinel() );
365
5.83k
    end_ = p;
366
5.83k
    if(BOOST_JSON_LIKELY(more_))
367
1.76k
    {
368
        // suspend
369
1.76k
        reserve();
370
1.76k
        st_.push_unchecked(n);
371
1.76k
        st_.push_unchecked(st);
372
1.76k
    }
373
5.83k
    return sentinel();
374
5.83k
}
375
376
template<class Handler>
377
const char*
378
basic_parser<Handler>::
379
maybe_suspend(
380
    const char* p,
381
    state st,
382
    const number& num)
383
339
{
384
339
    BOOST_ASSERT( p != sentinel() );
385
339
    end_ = p;
386
339
    if(BOOST_JSON_LIKELY(more_))
387
113
    {
388
        // suspend
389
113
        num_ = num;
390
113
        reserve();
391
113
        st_.push_unchecked(st);;
392
113
    }
393
339
    return sentinel();
394
339
}
395
396
template<class Handler>
397
const char*
398
basic_parser<Handler>::
399
suspend(
400
    const char* p,
401
    state st)
402
2.04k
{
403
2.04k
    BOOST_ASSERT( p != sentinel() );
404
2.04k
    end_ = p;
405
    // suspend
406
2.04k
    reserve();
407
2.04k
    st_.push_unchecked(st);
408
2.04k
    return sentinel();
409
2.04k
}
410
411
template<class Handler>
412
const char*
413
basic_parser<Handler>::
414
suspend(
415
    const char* p,
416
    state st,
417
    const number& num)
418
3.07k
{
419
3.07k
    BOOST_ASSERT( p != sentinel() );
420
3.07k
    end_ = p;
421
    // suspend
422
3.07k
    num_ = num;
423
3.07k
    reserve();
424
3.07k
    st_.push_unchecked(st);
425
3.07k
    return sentinel();
426
3.07k
}
427
428
template<class Handler>
429
template<
430
    bool StackEmpty_/*,
431
    bool Terminal_*/>
432
const char*
433
basic_parser<Handler>::
434
parse_comment(const char* p,
435
    std::integral_constant<bool, StackEmpty_> stack_empty,
436
    /*std::integral_constant<bool, Terminal_>*/ bool terminal)
437
5.28k
{
438
5.28k
    detail::const_stream_wrapper cs(p, end_);
439
5.28k
    const char* start = cs.begin();
440
5.28k
    std::size_t remain;
441
5.28k
    if(! stack_empty && ! st_.empty())
442
118
    {
443
118
        state st;
444
118
        st_.pop(st);
445
118
        switch(st)
446
118
        {
447
0
            default: BOOST_JSON_UNREACHABLE();
448
63
            case state::com1: goto do_com1;
449
19
            case state::com2: goto do_com2;
450
32
            case state::com3: goto do_com3;
451
4
            case state::com4: goto do_com4;
452
118
        }
453
118
    }
454
5.16k
    BOOST_ASSERT(*cs == '/');
455
5.16k
    ++cs;
456
5.22k
do_com1:
457
5.22k
    if(BOOST_JSON_UNLIKELY(! cs))
458
126
        return maybe_suspend(cs.begin(), state::com1);
459
5.10k
    switch(*cs)
460
5.10k
    {
461
23
    default:
462
23
        {
463
23
            BOOST_STATIC_CONSTEXPR source_location loc
464
23
                = BOOST_CURRENT_LOCATION;
465
23
            return fail(cs.begin(), error::syntax, &loc);
466
0
        }
467
4.71k
    case '/':
468
4.71k
        ++cs;
469
4.73k
do_com2:
470
        // KRYSTIAN TODO: this is a mess, we have to fix this
471
4.73k
        remain = cs.remain();
472
4.73k
        cs = remain ? static_cast<const char*>(
473
4.70k
            std::memchr(cs.begin(), '\n', remain)) : sentinel();
474
4.73k
        if(! cs.begin())
475
9
            cs = sentinel();
476
4.73k
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
477
38
        {
478
            // if the doc does not terminate
479
            // with a newline, treat it as the
480
            // end of the comment
481
38
            if(terminal && ! more_)
482
1
            {
483
1
                if(BOOST_JSON_UNLIKELY(! h_.on_comment(
484
1
                    {start, cs.remain(start)}, ec_)))
485
0
                    return fail(cs.end());
486
1
                return cs.end();
487
1
            }
488
37
            if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
489
37
                {start, cs.remain(start)}, ec_)))
490
0
                return fail(cs.end());
491
37
            if(terminal)
492
1
                return suspend(cs.end(), state::com2);
493
36
            return maybe_suspend(cs.end(), state::com2);
494
37
        }
495
4.69k
        break;
496
4.69k
    case '*':
497
365
        do
498
1.51k
        {
499
1.51k
            ++cs;
500
1.54k
do_com3:
501
            // KRYSTIAN TODO: this is a mess, we have to fix this
502
1.54k
            remain = cs.remain();
503
1.54k
            cs = remain ? static_cast<const char*>(
504
1.49k
                std::memchr(cs.begin(), '*', remain)) : sentinel();
505
1.54k
            if(! cs.begin())
506
17
                cs = sentinel();
507
            // stopped inside a c comment
508
1.54k
            if(BOOST_JSON_UNLIKELY(incomplete(cs)))
509
64
            {
510
64
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
511
64
                    {start, cs.remain(start)}, ec_)))
512
0
                    return fail(cs.end());
513
64
                return maybe_suspend(cs.end(), state::com3);
514
64
            }
515
            // found a asterisk, check if the next char is a slash
516
1.48k
            ++cs;
517
1.48k
do_com4:
518
1.48k
            if(BOOST_JSON_UNLIKELY(! cs))
519
8
            {
520
8
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
521
8
                    {start, cs.used(start)}, ec_)))
522
0
                    return fail(cs.begin());
523
8
                return maybe_suspend(cs.begin(), state::com4);
524
8
            }
525
1.48k
        }
526
1.47k
        while(*cs != '/');
527
5.10k
    }
528
5.02k
    ++cs;
529
5.02k
    if(BOOST_JSON_UNLIKELY(! h_.on_comment(
530
5.02k
        {start, cs.used(start)}, ec_)))
531
0
        return fail(cs.begin());
532
5.02k
    return cs.begin();
533
5.02k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_comment<true>(char const*, std::__1::integral_constant<bool, true>, bool)
Line
Count
Source
437
5.16k
{
438
5.16k
    detail::const_stream_wrapper cs(p, end_);
439
5.16k
    const char* start = cs.begin();
440
5.16k
    std::size_t remain;
441
5.16k
    if(! stack_empty && ! st_.empty())
442
0
    {
443
0
        state st;
444
0
        st_.pop(st);
445
0
        switch(st)
446
0
        {
447
0
            default: BOOST_JSON_UNREACHABLE();
448
0
            case state::com1: goto do_com1;
449
0
            case state::com2: goto do_com2;
450
0
            case state::com3: goto do_com3;
451
0
            case state::com4: goto do_com4;
452
0
        }
453
0
    }
454
5.16k
    BOOST_ASSERT(*cs == '/');
455
5.16k
    ++cs;
456
5.16k
do_com1:
457
5.16k
    if(BOOST_JSON_UNLIKELY(! cs))
458
63
        return maybe_suspend(cs.begin(), state::com1);
459
5.10k
    switch(*cs)
460
5.10k
    {
461
23
    default:
462
23
        {
463
23
            BOOST_STATIC_CONSTEXPR source_location loc
464
23
                = BOOST_CURRENT_LOCATION;
465
23
            return fail(cs.begin(), error::syntax, &loc);
466
0
        }
467
4.71k
    case '/':
468
4.71k
        ++cs;
469
4.71k
do_com2:
470
        // KRYSTIAN TODO: this is a mess, we have to fix this
471
4.71k
        remain = cs.remain();
472
4.71k
        cs = remain ? static_cast<const char*>(
473
4.70k
            std::memchr(cs.begin(), '\n', remain)) : sentinel();
474
4.71k
        if(! cs.begin())
475
9
            cs = sentinel();
476
4.71k
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
477
19
        {
478
            // if the doc does not terminate
479
            // with a newline, treat it as the
480
            // end of the comment
481
19
            if(terminal && ! more_)
482
0
            {
483
0
                if(BOOST_JSON_UNLIKELY(! h_.on_comment(
484
0
                    {start, cs.remain(start)}, ec_)))
485
0
                    return fail(cs.end());
486
0
                return cs.end();
487
0
            }
488
19
            if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
489
19
                {start, cs.remain(start)}, ec_)))
490
0
                return fail(cs.end());
491
19
            if(terminal)
492
1
                return suspend(cs.end(), state::com2);
493
18
            return maybe_suspend(cs.end(), state::com2);
494
19
        }
495
4.69k
        break;
496
4.69k
    case '*':
497
365
        do
498
1.51k
        {
499
1.51k
            ++cs;
500
1.51k
do_com3:
501
            // KRYSTIAN TODO: this is a mess, we have to fix this
502
1.51k
            remain = cs.remain();
503
1.51k
            cs = remain ? static_cast<const char*>(
504
1.49k
                std::memchr(cs.begin(), '*', remain)) : sentinel();
505
1.51k
            if(! cs.begin())
506
17
                cs = sentinel();
507
            // stopped inside a c comment
508
1.51k
            if(BOOST_JSON_UNLIKELY(incomplete(cs)))
509
32
            {
510
32
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
511
32
                    {start, cs.remain(start)}, ec_)))
512
0
                    return fail(cs.end());
513
32
                return maybe_suspend(cs.end(), state::com3);
514
32
            }
515
            // found a asterisk, check if the next char is a slash
516
1.48k
            ++cs;
517
1.48k
do_com4:
518
1.48k
            if(BOOST_JSON_UNLIKELY(! cs))
519
4
            {
520
4
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
521
4
                    {start, cs.used(start)}, ec_)))
522
0
                    return fail(cs.begin());
523
4
                return maybe_suspend(cs.begin(), state::com4);
524
4
            }
525
1.48k
        }
526
1.47k
        while(*cs != '/');
527
5.10k
    }
528
5.02k
    ++cs;
529
5.02k
    if(BOOST_JSON_UNLIKELY(! h_.on_comment(
530
5.02k
        {start, cs.used(start)}, ec_)))
531
0
        return fail(cs.begin());
532
5.02k
    return cs.begin();
533
5.02k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_comment<false>(char const*, std::__1::integral_constant<bool, false>, bool)
Line
Count
Source
437
118
{
438
118
    detail::const_stream_wrapper cs(p, end_);
439
118
    const char* start = cs.begin();
440
118
    std::size_t remain;
441
118
    if(! stack_empty && ! st_.empty())
442
118
    {
443
118
        state st;
444
118
        st_.pop(st);
445
118
        switch(st)
446
118
        {
447
0
            default: BOOST_JSON_UNREACHABLE();
448
63
            case state::com1: goto do_com1;
449
19
            case state::com2: goto do_com2;
450
32
            case state::com3: goto do_com3;
451
4
            case state::com4: goto do_com4;
452
118
        }
453
118
    }
454
0
    BOOST_ASSERT(*cs == '/');
455
0
    ++cs;
456
63
do_com1:
457
63
    if(BOOST_JSON_UNLIKELY(! cs))
458
63
        return maybe_suspend(cs.begin(), state::com1);
459
0
    switch(*cs)
460
0
    {
461
0
    default:
462
0
        {
463
0
            BOOST_STATIC_CONSTEXPR source_location loc
464
0
                = BOOST_CURRENT_LOCATION;
465
0
            return fail(cs.begin(), error::syntax, &loc);
466
0
        }
467
0
    case '/':
468
0
        ++cs;
469
19
do_com2:
470
        // KRYSTIAN TODO: this is a mess, we have to fix this
471
19
        remain = cs.remain();
472
19
        cs = remain ? static_cast<const char*>(
473
19
            std::memchr(cs.begin(), '\n', remain)) : sentinel();
474
19
        if(! cs.begin())
475
0
            cs = sentinel();
476
19
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
477
19
        {
478
            // if the doc does not terminate
479
            // with a newline, treat it as the
480
            // end of the comment
481
19
            if(terminal && ! more_)
482
1
            {
483
1
                if(BOOST_JSON_UNLIKELY(! h_.on_comment(
484
1
                    {start, cs.remain(start)}, ec_)))
485
0
                    return fail(cs.end());
486
1
                return cs.end();
487
1
            }
488
18
            if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
489
18
                {start, cs.remain(start)}, ec_)))
490
0
                return fail(cs.end());
491
18
            if(terminal)
492
0
                return suspend(cs.end(), state::com2);
493
18
            return maybe_suspend(cs.end(), state::com2);
494
18
        }
495
0
        break;
496
0
    case '*':
497
0
        do
498
0
        {
499
0
            ++cs;
500
32
do_com3:
501
            // KRYSTIAN TODO: this is a mess, we have to fix this
502
32
            remain = cs.remain();
503
32
            cs = remain ? static_cast<const char*>(
504
32
                std::memchr(cs.begin(), '*', remain)) : sentinel();
505
32
            if(! cs.begin())
506
0
                cs = sentinel();
507
            // stopped inside a c comment
508
32
            if(BOOST_JSON_UNLIKELY(incomplete(cs)))
509
32
            {
510
32
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
511
32
                    {start, cs.remain(start)}, ec_)))
512
0
                    return fail(cs.end());
513
32
                return maybe_suspend(cs.end(), state::com3);
514
32
            }
515
            // found a asterisk, check if the next char is a slash
516
0
            ++cs;
517
4
do_com4:
518
4
            if(BOOST_JSON_UNLIKELY(! cs))
519
4
            {
520
4
                if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
521
4
                    {start, cs.used(start)}, ec_)))
522
0
                    return fail(cs.begin());
523
4
                return maybe_suspend(cs.begin(), state::com4);
524
4
            }
525
4
        }
526
0
        while(*cs != '/');
527
0
    }
528
0
    ++cs;
529
0
    if(BOOST_JSON_UNLIKELY(! h_.on_comment(
530
0
        {start, cs.used(start)}, ec_)))
531
0
        return fail(cs.begin());
532
0
    return cs.begin();
533
0
}
534
535
template<class Handler>
536
template<bool StackEmpty_>
537
const char*
538
basic_parser<Handler>::
539
parse_document(const char* p,
540
    std::integral_constant<bool, StackEmpty_> stack_empty)
541
25.3k
{
542
25.3k
    detail::const_stream_wrapper cs(p, end_);
543
25.3k
    if(! stack_empty && ! st_.empty())
544
7.25k
    {
545
7.25k
        state st;
546
7.25k
        st_.peek(st);
547
7.25k
        switch(st)
548
7.25k
        {
549
5.14k
        default: goto do_doc2;
550
5.14k
        case state::doc1:
551
49
                 st_.pop(st);
552
49
                 goto do_doc1;
553
2.04k
        case state::doc3:
554
2.04k
                 st_.pop(st);
555
2.04k
                 goto do_doc3;
556
13
        case state::com1: case state::com2:
557
15
        case state::com3: case state::com4:
558
15
                 goto do_doc4;
559
7.25k
        }
560
7.25k
    }
561
18.1k
do_doc1:
562
18.1k
    cs = detail::count_whitespace(cs.begin(), cs.end());
563
18.1k
    if(BOOST_JSON_UNLIKELY(! cs))
564
122
        return maybe_suspend(cs.begin(), state::doc1);
565
23.2k
do_doc2:
566
23.2k
    switch(+opt_.allow_comments |
567
23.2k
        (opt_.allow_trailing_commas << 1) |
568
23.2k
        (opt_.allow_invalid_utf8 << 2))
569
23.2k
    {
570
    // no extensions
571
9.20k
    default:
572
9.20k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type());
573
9.20k
        break;
574
    // comments
575
1.64k
    case 1:
576
1.64k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type());
577
1.64k
        break;
578
    // trailing
579
1.41k
    case 2:
580
1.41k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type());
581
1.41k
        break;
582
    // comments & trailing
583
2.27k
    case 3:
584
2.27k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type());
585
2.27k
        break;
586
    // skip validation
587
1.18k
    case 4:
588
1.18k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type());
589
1.18k
        break;
590
    // comments & skip validation
591
1.91k
    case 5:
592
1.91k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type());
593
1.91k
        break;
594
    // trailing & skip validation
595
2.82k
    case 6:
596
2.82k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type());
597
2.82k
        break;
598
    // comments & trailing & skip validation
599
2.73k
    case 7:
600
2.73k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type());
601
2.73k
        break;
602
23.2k
    }
603
23.0k
    if(BOOST_JSON_UNLIKELY(incomplete(cs)))
604
        // the appropriate state has already been pushed into stack
605
14.4k
        return sentinel();
606
11.2k
do_doc3:
607
11.2k
    cs = detail::count_whitespace(cs.begin(), cs.end());
608
11.2k
    if(BOOST_JSON_UNLIKELY(! cs))
609
9.01k
    {
610
9.01k
        if(more_)
611
2.04k
            return suspend(cs.begin(), state::doc3);
612
9.01k
    }
613
2.27k
    else if(opt_.allow_comments && *cs == '/')
614
636
    {
615
651
do_doc4:
616
651
        cs = parse_comment(cs.begin(), stack_empty, std::true_type());
617
651
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
618
31
            return sentinel();
619
620
        goto do_doc3;
620
651
    }
621
8.61k
    return cs.begin();
622
11.2k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_document<true>(char const*, std::__1::integral_constant<bool, true>)
Line
Count
Source
541
18.1k
{
542
18.1k
    detail::const_stream_wrapper cs(p, end_);
543
18.1k
    if(! stack_empty && ! st_.empty())
544
0
    {
545
0
        state st;
546
0
        st_.peek(st);
547
0
        switch(st)
548
0
        {
549
0
        default: goto do_doc2;
550
0
        case state::doc1:
551
0
                 st_.pop(st);
552
0
                 goto do_doc1;
553
0
        case state::doc3:
554
0
                 st_.pop(st);
555
0
                 goto do_doc3;
556
0
        case state::com1: case state::com2:
557
0
        case state::com3: case state::com4:
558
0
                 goto do_doc4;
559
0
        }
560
0
    }
561
18.1k
do_doc1:
562
18.1k
    cs = detail::count_whitespace(cs.begin(), cs.end());
563
18.1k
    if(BOOST_JSON_UNLIKELY(! cs))
564
73
        return maybe_suspend(cs.begin(), state::doc1);
565
18.0k
do_doc2:
566
18.0k
    switch(+opt_.allow_comments |
567
18.0k
        (opt_.allow_trailing_commas << 1) |
568
18.0k
        (opt_.allow_invalid_utf8 << 2))
569
18.0k
    {
570
    // no extensions
571
8.43k
    default:
572
8.43k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type());
573
8.43k
        break;
574
    // comments
575
1.06k
    case 1:
576
1.06k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type());
577
1.06k
        break;
578
    // trailing
579
949
    case 2:
580
949
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type());
581
949
        break;
582
    // comments & trailing
583
1.55k
    case 3:
584
1.55k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type());
585
1.55k
        break;
586
    // skip validation
587
763
    case 4:
588
763
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type());
589
763
        break;
590
    // comments & skip validation
591
1.32k
    case 5:
592
1.32k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type());
593
1.32k
        break;
594
    // trailing & skip validation
595
2.03k
    case 6:
596
2.03k
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type());
597
2.03k
        break;
598
    // comments & trailing & skip validation
599
1.92k
    case 7:
600
1.92k
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type());
601
1.92k
        break;
602
18.0k
    }
603
17.9k
    if(BOOST_JSON_UNLIKELY(incomplete(cs)))
604
        // the appropriate state has already been pushed into stack
605
11.9k
        return sentinel();
606
6.64k
do_doc3:
607
6.64k
    cs = detail::count_whitespace(cs.begin(), cs.end());
608
6.64k
    if(BOOST_JSON_UNLIKELY(! cs))
609
4.37k
    {
610
4.37k
        if(more_)
611
2.04k
            return suspend(cs.begin(), state::doc3);
612
4.37k
    }
613
2.27k
    else if(opt_.allow_comments && *cs == '/')
614
636
    {
615
636
do_doc4:
616
636
        cs = parse_comment(cs.begin(), stack_empty, std::true_type());
617
636
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
618
17
            return sentinel();
619
619
        goto do_doc3;
620
636
    }
621
3.97k
    return cs.begin();
622
6.64k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_document<false>(char const*, std::__1::integral_constant<bool, false>)
Line
Count
Source
541
7.25k
{
542
7.25k
    detail::const_stream_wrapper cs(p, end_);
543
7.25k
    if(! stack_empty && ! st_.empty())
544
7.25k
    {
545
7.25k
        state st;
546
7.25k
        st_.peek(st);
547
7.25k
        switch(st)
548
7.25k
        {
549
5.14k
        default: goto do_doc2;
550
5.14k
        case state::doc1:
551
49
                 st_.pop(st);
552
49
                 goto do_doc1;
553
2.04k
        case state::doc3:
554
2.04k
                 st_.pop(st);
555
2.04k
                 goto do_doc3;
556
13
        case state::com1: case state::com2:
557
15
        case state::com3: case state::com4:
558
15
                 goto do_doc4;
559
7.25k
        }
560
7.25k
    }
561
49
do_doc1:
562
49
    cs = detail::count_whitespace(cs.begin(), cs.end());
563
49
    if(BOOST_JSON_UNLIKELY(! cs))
564
49
        return maybe_suspend(cs.begin(), state::doc1);
565
5.14k
do_doc2:
566
5.14k
    switch(+opt_.allow_comments |
567
5.14k
        (opt_.allow_trailing_commas << 1) |
568
5.14k
        (opt_.allow_invalid_utf8 << 2))
569
5.14k
    {
570
    // no extensions
571
764
    default:
572
764
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type());
573
764
        break;
574
    // comments
575
580
    case 1:
576
580
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type());
577
580
        break;
578
    // trailing
579
468
    case 2:
580
468
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type());
581
468
        break;
582
    // comments & trailing
583
721
    case 3:
584
721
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type());
585
721
        break;
586
    // skip validation
587
421
    case 4:
588
421
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type());
589
421
        break;
590
    // comments & skip validation
591
598
    case 5:
592
598
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type());
593
598
        break;
594
    // trailing & skip validation
595
781
    case 6:
596
781
        cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type());
597
781
        break;
598
    // comments & trailing & skip validation
599
813
    case 7:
600
813
        cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type());
601
813
        break;
602
5.14k
    }
603
5.11k
    if(BOOST_JSON_UNLIKELY(incomplete(cs)))
604
        // the appropriate state has already been pushed into stack
605
2.51k
        return sentinel();
606
4.64k
do_doc3:
607
4.64k
    cs = detail::count_whitespace(cs.begin(), cs.end());
608
4.64k
    if(BOOST_JSON_UNLIKELY(! cs))
609
4.64k
    {
610
4.64k
        if(more_)
611
0
            return suspend(cs.begin(), state::doc3);
612
4.64k
    }
613
0
    else if(opt_.allow_comments && *cs == '/')
614
0
    {
615
15
do_doc4:
616
15
        cs = parse_comment(cs.begin(), stack_empty, std::true_type());
617
15
        if(BOOST_JSON_UNLIKELY(incomplete(cs)))
618
14
            return sentinel();
619
1
        goto do_doc3;
620
15
    }
621
4.64k
    return cs.begin();
622
4.64k
}
623
624
template<class Handler>
625
template<
626
    bool StackEmpty_,
627
    bool AllowComments_/*,
628
    bool AllowTrailing_,
629
    bool AllowBadUTF8_*/>
630
const char*
631
basic_parser<Handler>::
632
parse_value(const char* p,
633
    std::integral_constant<bool, StackEmpty_> stack_empty,
634
    std::integral_constant<bool, AllowComments_> allow_comments,
635
    /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
636
    /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8)
637
10.8M
{
638
10.8M
    if(stack_empty || st_.empty())
639
10.8M
    {
640
10.8M
loop:
641
10.8M
        switch(*p)
642
10.8M
        {
643
228k
        case '0':
644
228k
            return mp11::mp_with_index<3>(
645
228k
                static_cast<unsigned char>(opt_.numbers),
646
228k
                parse_number_helper<true, '0'>{ this, p });
647
37.1k
        case '-':
648
37.1k
            return mp11::mp_with_index<3>(
649
37.1k
                static_cast<unsigned char>(opt_.numbers),
650
37.1k
                parse_number_helper<true, '-'>{ this, p });
651
6.07M
        case '1': case '2': case '3':
652
6.57M
        case '4': case '5': case '6':
653
10.3M
        case '7': case '8': case '9':
654
10.3M
            return mp11::mp_with_index<3>(
655
10.3M
                static_cast<unsigned char>(opt_.numbers),
656
10.3M
                parse_number_helper<true, '+'>{ this, p });
657
13.7k
        case 'n':
658
13.7k
            return parse_literal( p, mp11::mp_int<detail::null_literal>() );
659
22.5k
        case 't':
660
22.5k
            return parse_literal( p, mp11::mp_int<detail::true_literal>() );
661
21.7k
        case 'f':
662
21.7k
            return parse_literal( p, mp11::mp_int<detail::false_literal>() );
663
5
        case 'I':
664
5
            if( !opt_.allow_infinity_and_nan )
665
5
            {
666
5
                BOOST_STATIC_CONSTEXPR source_location loc
667
5
                    = BOOST_CURRENT_LOCATION;
668
5
                return fail(p, error::syntax, &loc);
669
5
            }
670
0
            return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
671
6
        case 'N':
672
6
            if( !opt_.allow_infinity_and_nan )
673
6
            {
674
6
                BOOST_STATIC_CONSTEXPR source_location loc
675
6
                    = BOOST_CURRENT_LOCATION;
676
6
                return fail(p, error::syntax, &loc);
677
6
            }
678
0
            return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
679
82.4k
        case '"':
680
82.4k
            return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
681
20.2k
        case '[':
682
20.2k
            return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
683
22.4k
        case '{':
684
22.4k
            return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
685
1.50k
        case '/':
686
1.50k
            if(! allow_comments)
687
3
            {
688
3
                BOOST_STATIC_CONSTEXPR source_location loc
689
3
                    = BOOST_CURRENT_LOCATION;
690
3
                return fail(p, error::syntax, &loc);
691
3
            }
692
1.50k
            p = parse_comment(p, stack_empty, std::false_type());
693
            // KRYSTIAN NOTE: incomplete takes const_stream, we either
694
            // can add an overload, change the existing one to take a pointer,
695
            // or just leave it as is
696
1.50k
            if(BOOST_JSON_UNLIKELY(p == sentinel()))
697
67
                return maybe_suspend(p, state::val2);
698
            // intentional fallthrough
699
1.43k
        case ' ':
700
1.43k
        case '\t':
701
1.43k
        case '\n':
702
1.43k
        case '\r':
703
1.43k
            p = detail::count_whitespace(p, end_);
704
1.43k
            if(BOOST_JSON_UNLIKELY(p == end_))
705
41
                return maybe_suspend(p, state::val1);
706
1.39k
            goto loop;
707
1.39k
        default:
708
658
            {
709
658
                BOOST_STATIC_CONSTEXPR source_location loc
710
658
                    = BOOST_CURRENT_LOCATION;
711
658
                return fail(p, error::syntax, &loc);
712
1.43k
            }
713
10.8M
        }
714
10.8M
    }
715
7.07k
    return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8);
716
10.8M
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_value<true, false>(char const*, std::__1::integral_constant<bool, true>, std::__1::integral_constant<bool, false>, bool, bool)
Line
Count
Source
637
6.08M
{
638
6.08M
    if(stack_empty || st_.empty())
639
6.08M
    {
640
6.08M
loop:
641
6.08M
        switch(*p)
642
6.08M
        {
643
187k
        case '0':
644
187k
            return mp11::mp_with_index<3>(
645
187k
                static_cast<unsigned char>(opt_.numbers),
646
187k
                parse_number_helper<true, '0'>{ this, p });
647
28.6k
        case '-':
648
28.6k
            return mp11::mp_with_index<3>(
649
28.6k
                static_cast<unsigned char>(opt_.numbers),
650
28.6k
                parse_number_helper<true, '-'>{ this, p });
651
2.83M
        case '1': case '2': case '3':
652
3.28M
        case '4': case '5': case '6':
653
5.72M
        case '7': case '8': case '9':
654
5.72M
            return mp11::mp_with_index<3>(
655
5.72M
                static_cast<unsigned char>(opt_.numbers),
656
5.72M
                parse_number_helper<true, '+'>{ this, p });
657
8.52k
        case 'n':
658
8.52k
            return parse_literal( p, mp11::mp_int<detail::null_literal>() );
659
15.7k
        case 't':
660
15.7k
            return parse_literal( p, mp11::mp_int<detail::true_literal>() );
661
19.5k
        case 'f':
662
19.5k
            return parse_literal( p, mp11::mp_int<detail::false_literal>() );
663
3
        case 'I':
664
3
            if( !opt_.allow_infinity_and_nan )
665
3
            {
666
3
                BOOST_STATIC_CONSTEXPR source_location loc
667
3
                    = BOOST_CURRENT_LOCATION;
668
3
                return fail(p, error::syntax, &loc);
669
3
            }
670
0
            return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
671
4
        case 'N':
672
4
            if( !opt_.allow_infinity_and_nan )
673
4
            {
674
4
                BOOST_STATIC_CONSTEXPR source_location loc
675
4
                    = BOOST_CURRENT_LOCATION;
676
4
                return fail(p, error::syntax, &loc);
677
4
            }
678
0
            return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
679
71.2k
        case '"':
680
71.2k
            return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
681
12.0k
        case '[':
682
12.0k
            return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
683
15.5k
        case '{':
684
15.5k
            return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
685
3
        case '/':
686
3
            if(! allow_comments)
687
3
            {
688
3
                BOOST_STATIC_CONSTEXPR source_location loc
689
3
                    = BOOST_CURRENT_LOCATION;
690
3
                return fail(p, error::syntax, &loc);
691
3
            }
692
0
            p = parse_comment(p, stack_empty, std::false_type());
693
            // KRYSTIAN NOTE: incomplete takes const_stream, we either
694
            // can add an overload, change the existing one to take a pointer,
695
            // or just leave it as is
696
0
            if(BOOST_JSON_UNLIKELY(p == sentinel()))
697
0
                return maybe_suspend(p, state::val2);
698
            // intentional fallthrough
699
0
        case ' ':
700
0
        case '\t':
701
0
        case '\n':
702
0
        case '\r':
703
0
            p = detail::count_whitespace(p, end_);
704
0
            if(BOOST_JSON_UNLIKELY(p == end_))
705
0
                return maybe_suspend(p, state::val1);
706
0
            goto loop;
707
410
        default:
708
410
            {
709
410
                BOOST_STATIC_CONSTEXPR source_location loc
710
410
                    = BOOST_CURRENT_LOCATION;
711
410
                return fail(p, error::syntax, &loc);
712
0
            }
713
6.08M
        }
714
6.08M
    }
715
0
    return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8);
716
6.08M
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_value<true, true>(char const*, std::__1::integral_constant<bool, true>, std::__1::integral_constant<bool, true>, bool, bool)
Line
Count
Source
637
4.74M
{
638
4.74M
    if(stack_empty || st_.empty())
639
4.74M
    {
640
4.74M
loop:
641
4.74M
        switch(*p)
642
4.74M
        {
643
41.2k
        case '0':
644
41.2k
            return mp11::mp_with_index<3>(
645
41.2k
                static_cast<unsigned char>(opt_.numbers),
646
41.2k
                parse_number_helper<true, '0'>{ this, p });
647
8.50k
        case '-':
648
8.50k
            return mp11::mp_with_index<3>(
649
8.50k
                static_cast<unsigned char>(opt_.numbers),
650
8.50k
                parse_number_helper<true, '-'>{ this, p });
651
3.23M
        case '1': case '2': case '3':
652
3.28M
        case '4': case '5': case '6':
653
4.65M
        case '7': case '8': case '9':
654
4.65M
            return mp11::mp_with_index<3>(
655
4.65M
                static_cast<unsigned char>(opt_.numbers),
656
4.65M
                parse_number_helper<true, '+'>{ this, p });
657
5.26k
        case 'n':
658
5.26k
            return parse_literal( p, mp11::mp_int<detail::null_literal>() );
659
6.85k
        case 't':
660
6.85k
            return parse_literal( p, mp11::mp_int<detail::true_literal>() );
661
2.18k
        case 'f':
662
2.18k
            return parse_literal( p, mp11::mp_int<detail::false_literal>() );
663
2
        case 'I':
664
2
            if( !opt_.allow_infinity_and_nan )
665
2
            {
666
2
                BOOST_STATIC_CONSTEXPR source_location loc
667
2
                    = BOOST_CURRENT_LOCATION;
668
2
                return fail(p, error::syntax, &loc);
669
2
            }
670
0
            return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
671
2
        case 'N':
672
2
            if( !opt_.allow_infinity_and_nan )
673
2
            {
674
2
                BOOST_STATIC_CONSTEXPR source_location loc
675
2
                    = BOOST_CURRENT_LOCATION;
676
2
                return fail(p, error::syntax, &loc);
677
2
            }
678
0
            return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
679
11.1k
        case '"':
680
11.1k
            return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
681
8.17k
        case '[':
682
8.17k
            return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
683
6.91k
        case '{':
684
6.91k
            return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
685
1.50k
        case '/':
686
1.50k
            if(! allow_comments)
687
0
            {
688
0
                BOOST_STATIC_CONSTEXPR source_location loc
689
0
                    = BOOST_CURRENT_LOCATION;
690
0
                return fail(p, error::syntax, &loc);
691
0
            }
692
1.50k
            p = parse_comment(p, stack_empty, std::false_type());
693
            // KRYSTIAN NOTE: incomplete takes const_stream, we either
694
            // can add an overload, change the existing one to take a pointer,
695
            // or just leave it as is
696
1.50k
            if(BOOST_JSON_UNLIKELY(p == sentinel()))
697
67
                return maybe_suspend(p, state::val2);
698
            // intentional fallthrough
699
1.43k
        case ' ':
700
1.43k
        case '\t':
701
1.43k
        case '\n':
702
1.43k
        case '\r':
703
1.43k
            p = detail::count_whitespace(p, end_);
704
1.43k
            if(BOOST_JSON_UNLIKELY(p == end_))
705
41
                return maybe_suspend(p, state::val1);
706
1.39k
            goto loop;
707
1.39k
        default:
708
248
            {
709
248
                BOOST_STATIC_CONSTEXPR source_location loc
710
248
                    = BOOST_CURRENT_LOCATION;
711
248
                return fail(p, error::syntax, &loc);
712
1.43k
            }
713
4.74M
        }
714
4.74M
    }
715
0
    return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8);
716
4.74M
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_value<false, false>(char const*, std::__1::integral_constant<bool, false>, std::__1::integral_constant<bool, false>, bool, bool)
Line
Count
Source
637
3.30k
{
638
3.30k
    if(stack_empty || st_.empty())
639
0
    {
640
0
loop:
641
0
        switch(*p)
642
0
        {
643
0
        case '0':
644
0
            return mp11::mp_with_index<3>(
645
0
                static_cast<unsigned char>(opt_.numbers),
646
0
                parse_number_helper<true, '0'>{ this, p });
647
0
        case '-':
648
0
            return mp11::mp_with_index<3>(
649
0
                static_cast<unsigned char>(opt_.numbers),
650
0
                parse_number_helper<true, '-'>{ this, p });
651
0
        case '1': case '2': case '3':
652
0
        case '4': case '5': case '6':
653
0
        case '7': case '8': case '9':
654
0
            return mp11::mp_with_index<3>(
655
0
                static_cast<unsigned char>(opt_.numbers),
656
0
                parse_number_helper<true, '+'>{ this, p });
657
0
        case 'n':
658
0
            return parse_literal( p, mp11::mp_int<detail::null_literal>() );
659
0
        case 't':
660
0
            return parse_literal( p, mp11::mp_int<detail::true_literal>() );
661
0
        case 'f':
662
0
            return parse_literal( p, mp11::mp_int<detail::false_literal>() );
663
0
        case 'I':
664
0
            if( !opt_.allow_infinity_and_nan )
665
0
            {
666
0
                BOOST_STATIC_CONSTEXPR source_location loc
667
0
                    = BOOST_CURRENT_LOCATION;
668
0
                return fail(p, error::syntax, &loc);
669
0
            }
670
0
            return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
671
0
        case 'N':
672
0
            if( !opt_.allow_infinity_and_nan )
673
0
            {
674
0
                BOOST_STATIC_CONSTEXPR source_location loc
675
0
                    = BOOST_CURRENT_LOCATION;
676
0
                return fail(p, error::syntax, &loc);
677
0
            }
678
0
            return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
679
0
        case '"':
680
0
            return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
681
0
        case '[':
682
0
            return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
683
0
        case '{':
684
0
            return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
685
0
        case '/':
686
0
            if(! allow_comments)
687
0
            {
688
0
                BOOST_STATIC_CONSTEXPR source_location loc
689
0
                    = BOOST_CURRENT_LOCATION;
690
0
                return fail(p, error::syntax, &loc);
691
0
            }
692
0
            p = parse_comment(p, stack_empty, std::false_type());
693
            // KRYSTIAN NOTE: incomplete takes const_stream, we either
694
            // can add an overload, change the existing one to take a pointer,
695
            // or just leave it as is
696
0
            if(BOOST_JSON_UNLIKELY(p == sentinel()))
697
0
                return maybe_suspend(p, state::val2);
698
            // intentional fallthrough
699
0
        case ' ':
700
0
        case '\t':
701
0
        case '\n':
702
0
        case '\r':
703
0
            p = detail::count_whitespace(p, end_);
704
0
            if(BOOST_JSON_UNLIKELY(p == end_))
705
0
                return maybe_suspend(p, state::val1);
706
0
            goto loop;
707
0
        default:
708
0
            {
709
0
                BOOST_STATIC_CONSTEXPR source_location loc
710
0
                    = BOOST_CURRENT_LOCATION;
711
0
                return fail(p, error::syntax, &loc);
712
0
            }
713
0
        }
714
0
    }
715
3.30k
    return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8);
716
3.30k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_value<false, true>(char const*, std::__1::integral_constant<bool, false>, std::__1::integral_constant<bool, true>, bool, bool)
Line
Count
Source
637
3.77k
{
638
3.77k
    if(stack_empty || st_.empty())
639
0
    {
640
0
loop:
641
0
        switch(*p)
642
0
        {
643
0
        case '0':
644
0
            return mp11::mp_with_index<3>(
645
0
                static_cast<unsigned char>(opt_.numbers),
646
0
                parse_number_helper<true, '0'>{ this, p });
647
0
        case '-':
648
0
            return mp11::mp_with_index<3>(
649
0
                static_cast<unsigned char>(opt_.numbers),
650
0
                parse_number_helper<true, '-'>{ this, p });
651
0
        case '1': case '2': case '3':
652
0
        case '4': case '5': case '6':
653
0
        case '7': case '8': case '9':
654
0
            return mp11::mp_with_index<3>(
655
0
                static_cast<unsigned char>(opt_.numbers),
656
0
                parse_number_helper<true, '+'>{ this, p });
657
0
        case 'n':
658
0
            return parse_literal( p, mp11::mp_int<detail::null_literal>() );
659
0
        case 't':
660
0
            return parse_literal( p, mp11::mp_int<detail::true_literal>() );
661
0
        case 'f':
662
0
            return parse_literal( p, mp11::mp_int<detail::false_literal>() );
663
0
        case 'I':
664
0
            if( !opt_.allow_infinity_and_nan )
665
0
            {
666
0
                BOOST_STATIC_CONSTEXPR source_location loc
667
0
                    = BOOST_CURRENT_LOCATION;
668
0
                return fail(p, error::syntax, &loc);
669
0
            }
670
0
            return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
671
0
        case 'N':
672
0
            if( !opt_.allow_infinity_and_nan )
673
0
            {
674
0
                BOOST_STATIC_CONSTEXPR source_location loc
675
0
                    = BOOST_CURRENT_LOCATION;
676
0
                return fail(p, error::syntax, &loc);
677
0
            }
678
0
            return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
679
0
        case '"':
680
0
            return parse_unescaped(p, std::true_type(), std::false_type(), allow_bad_utf8);
681
0
        case '[':
682
0
            return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
683
0
        case '{':
684
0
            return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
685
0
        case '/':
686
0
            if(! allow_comments)
687
0
            {
688
0
                BOOST_STATIC_CONSTEXPR source_location loc
689
0
                    = BOOST_CURRENT_LOCATION;
690
0
                return fail(p, error::syntax, &loc);
691
0
            }
692
0
            p = parse_comment(p, stack_empty, std::false_type());
693
            // KRYSTIAN NOTE: incomplete takes const_stream, we either
694
            // can add an overload, change the existing one to take a pointer,
695
            // or just leave it as is
696
0
            if(BOOST_JSON_UNLIKELY(p == sentinel()))
697
0
                return maybe_suspend(p, state::val2);
698
            // intentional fallthrough
699
0
        case ' ':
700
0
        case '\t':
701
0
        case '\n':
702
0
        case '\r':
703
0
            p = detail::count_whitespace(p, end_);
704
0
            if(BOOST_JSON_UNLIKELY(p == end_))
705
0
                return maybe_suspend(p, state::val1);
706
0
            goto loop;
707
0
        default:
708
0
            {
709
0
                BOOST_STATIC_CONSTEXPR source_location loc
710
0
                    = BOOST_CURRENT_LOCATION;
711
0
                return fail(p, error::syntax, &loc);
712
0
            }
713
0
        }
714
0
    }
715
3.77k
    return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8);
716
3.77k
}
717
718
template<class Handler>
719
template<
720
    bool AllowComments_/*,
721
    bool AllowTrailing_,
722
    bool AllowBadUTF8_*/>
723
const char*
724
basic_parser<Handler>::
725
resume_value(const char* p,
726
    std::integral_constant<bool, AllowComments_> allow_comments,
727
    /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
728
    /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8)
729
7.07k
{
730
7.07k
    state st;
731
7.07k
    st_.peek(st);
732
7.07k
    switch(st)
733
7.07k
    {
734
0
    default: BOOST_JSON_UNREACHABLE();
735
53
    case state::lit1:
736
53
        return parse_literal(p,  mp11::mp_int<detail::resume_literal>() );
737
738
155
    case state::str1:
739
155
        return parse_unescaped(p, std::false_type(), std::false_type(), allow_bad_utf8);
740
741
350
    case state::str2: case state::str3:
742
383
    case state::str4: case state::str5:
743
414
    case state::str6: case state::str7:
744
476
    case state::str8:
745
489
    case state::sur1: case state::sur2:
746
503
    case state::sur3: case state::sur4:
747
521
    case state::sur5: case state::sur6:
748
521
        return parse_escaped(p, 0, std::false_type(), std::false_type(), allow_bad_utf8);
749
750
102
    case state::arr1: case state::arr2:
751
1.63k
    case state::arr3: case state::arr4:
752
1.77k
    case state::arr5: case state::arr6:
753
1.77k
        return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
754
755
88
    case state::obj1: case state::obj2:
756
420
    case state::obj3: case state::obj4:
757
484
    case state::obj5: case state::obj6:
758
1.20k
    case state::obj7: case state::obj8:
759
1.27k
    case state::obj9: case state::obj10:
760
1.28k
    case state::obj11:
761
1.28k
        return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
762
763
837
    case state::num1: case state::num2:
764
926
    case state::num3: case state::num4:
765
1.06k
    case state::num5: case state::num6:
766
2.12k
    case state::num7: case state::num8:
767
2.24k
    case state::exp1: case state::exp2:
768
3.18k
    case state::exp3:
769
3.18k
        return mp11::mp_with_index<3>(
770
3.18k
            static_cast<unsigned char>(opt_.numbers),
771
3.18k
            parse_number_helper<false, 0>{ this, p });
772
773
    // KRYSTIAN NOTE: these are special cases
774
41
    case state::val1:
775
41
    {
776
41
        st_.pop(st);
777
41
        BOOST_ASSERT(st_.empty());
778
41
        p = detail::count_whitespace(p, end_);
779
41
        if(BOOST_JSON_UNLIKELY(p == end_))
780
41
            return maybe_suspend(p, state::val1);
781
0
        return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
782
41
    }
783
784
59
    case state::val2:
785
59
    {
786
59
        st_.pop(st);
787
59
        p = parse_comment(p, std::false_type(), std::false_type());
788
59
        if(BOOST_JSON_UNLIKELY(p == sentinel()))
789
59
            return maybe_suspend(p, state::val2);
790
0
        if(BOOST_JSON_UNLIKELY( p == end_ ))
791
0
            return maybe_suspend(p, state::val3);
792
0
        BOOST_ASSERT(st_.empty());
793
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
794
0
    }
795
796
0
    case state::val3:
797
0
    {
798
0
        st_.pop(st);
799
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
800
0
    }
801
7.07k
    }
802
7.07k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::resume_value<false>(char const*, std::__1::integral_constant<bool, false>, bool, bool)
Line
Count
Source
729
3.30k
{
730
3.30k
    state st;
731
3.30k
    st_.peek(st);
732
3.30k
    switch(st)
733
3.30k
    {
734
0
    default: BOOST_JSON_UNREACHABLE();
735
26
    case state::lit1:
736
26
        return parse_literal(p,  mp11::mp_int<detail::resume_literal>() );
737
738
68
    case state::str1:
739
68
        return parse_unescaped(p, std::false_type(), std::false_type(), allow_bad_utf8);
740
741
171
    case state::str2: case state::str3:
742
185
    case state::str4: case state::str5:
743
203
    case state::str6: case state::str7:
744
233
    case state::str8:
745
239
    case state::sur1: case state::sur2:
746
242
    case state::sur3: case state::sur4:
747
251
    case state::sur5: case state::sur6:
748
251
        return parse_escaped(p, 0, std::false_type(), std::false_type(), allow_bad_utf8);
749
750
39
    case state::arr1: case state::arr2:
751
746
    case state::arr3: case state::arr4:
752
818
    case state::arr5: case state::arr6:
753
818
        return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
754
755
38
    case state::obj1: case state::obj2:
756
207
    case state::obj3: case state::obj4:
757
235
    case state::obj5: case state::obj6:
758
550
    case state::obj7: case state::obj8:
759
577
    case state::obj9: case state::obj10:
760
577
    case state::obj11:
761
577
        return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
762
763
433
    case state::num1: case state::num2:
764
481
    case state::num3: case state::num4:
765
557
    case state::num5: case state::num6:
766
1.02k
    case state::num7: case state::num8:
767
1.08k
    case state::exp1: case state::exp2:
768
1.56k
    case state::exp3:
769
1.56k
        return mp11::mp_with_index<3>(
770
1.56k
            static_cast<unsigned char>(opt_.numbers),
771
1.56k
            parse_number_helper<false, 0>{ this, p });
772
773
    // KRYSTIAN NOTE: these are special cases
774
0
    case state::val1:
775
0
    {
776
0
        st_.pop(st);
777
0
        BOOST_ASSERT(st_.empty());
778
0
        p = detail::count_whitespace(p, end_);
779
0
        if(BOOST_JSON_UNLIKELY(p == end_))
780
0
            return maybe_suspend(p, state::val1);
781
0
        return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
782
0
    }
783
784
0
    case state::val2:
785
0
    {
786
0
        st_.pop(st);
787
0
        p = parse_comment(p, std::false_type(), std::false_type());
788
0
        if(BOOST_JSON_UNLIKELY(p == sentinel()))
789
0
            return maybe_suspend(p, state::val2);
790
0
        if(BOOST_JSON_UNLIKELY( p == end_ ))
791
0
            return maybe_suspend(p, state::val3);
792
0
        BOOST_ASSERT(st_.empty());
793
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
794
0
    }
795
796
0
    case state::val3:
797
0
    {
798
0
        st_.pop(st);
799
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
800
0
    }
801
3.30k
    }
802
3.30k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::resume_value<true>(char const*, std::__1::integral_constant<bool, true>, bool, bool)
Line
Count
Source
729
3.77k
{
730
3.77k
    state st;
731
3.77k
    st_.peek(st);
732
3.77k
    switch(st)
733
3.77k
    {
734
0
    default: BOOST_JSON_UNREACHABLE();
735
27
    case state::lit1:
736
27
        return parse_literal(p,  mp11::mp_int<detail::resume_literal>() );
737
738
87
    case state::str1:
739
87
        return parse_unescaped(p, std::false_type(), std::false_type(), allow_bad_utf8);
740
741
179
    case state::str2: case state::str3:
742
198
    case state::str4: case state::str5:
743
211
    case state::str6: case state::str7:
744
243
    case state::str8:
745
250
    case state::sur1: case state::sur2:
746
261
    case state::sur3: case state::sur4:
747
270
    case state::sur5: case state::sur6:
748
270
        return parse_escaped(p, 0, std::false_type(), std::false_type(), allow_bad_utf8);
749
750
63
    case state::arr1: case state::arr2:
751
884
    case state::arr3: case state::arr4:
752
959
    case state::arr5: case state::arr6:
753
959
        return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
754
755
50
    case state::obj1: case state::obj2:
756
213
    case state::obj3: case state::obj4:
757
249
    case state::obj5: case state::obj6:
758
653
    case state::obj7: case state::obj8:
759
699
    case state::obj9: case state::obj10:
760
704
    case state::obj11:
761
704
        return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8);
762
763
404
    case state::num1: case state::num2:
764
445
    case state::num3: case state::num4:
765
510
    case state::num5: case state::num6:
766
1.09k
    case state::num7: case state::num8:
767
1.15k
    case state::exp1: case state::exp2:
768
1.62k
    case state::exp3:
769
1.62k
        return mp11::mp_with_index<3>(
770
1.62k
            static_cast<unsigned char>(opt_.numbers),
771
1.62k
            parse_number_helper<false, 0>{ this, p });
772
773
    // KRYSTIAN NOTE: these are special cases
774
41
    case state::val1:
775
41
    {
776
41
        st_.pop(st);
777
41
        BOOST_ASSERT(st_.empty());
778
41
        p = detail::count_whitespace(p, end_);
779
41
        if(BOOST_JSON_UNLIKELY(p == end_))
780
41
            return maybe_suspend(p, state::val1);
781
0
        return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8);
782
41
    }
783
784
59
    case state::val2:
785
59
    {
786
59
        st_.pop(st);
787
59
        p = parse_comment(p, std::false_type(), std::false_type());
788
59
        if(BOOST_JSON_UNLIKELY(p == sentinel()))
789
59
            return maybe_suspend(p, state::val2);
790
0
        if(BOOST_JSON_UNLIKELY( p == end_ ))
791
0
            return maybe_suspend(p, state::val3);
792
0
        BOOST_ASSERT(st_.empty());
793
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
794
0
    }
795
796
0
    case state::val3:
797
0
    {
798
0
        st_.pop(st);
799
0
        return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8);
800
0
    }
801
3.77k
    }
802
3.77k
}
803
804
template<class Handler>
805
template<int Literal>
806
const char*
807
basic_parser<Handler>::
808
parse_literal(const char* p,
809
    std::integral_constant<int, Literal> literal)
810
58.1k
{
811
58.1k
    constexpr char const* literals[] = {
812
58.1k
        "null",
813
58.1k
        "true",
814
58.1k
        "false",
815
58.1k
        "Infinity",
816
58.1k
        "-Infinity",
817
58.1k
        "NaN",
818
58.1k
    };
819
820
58.1k
    constexpr std::size_t literal_sizes[] = {
821
58.1k
        4,
822
58.1k
        4,
823
58.1k
        5,
824
58.1k
        8,
825
58.1k
        9,
826
58.1k
        3,
827
58.1k
    };
828
829
58.1k
    std::size_t cur_lit;
830
58.1k
    std::size_t offset;
831
832
58.1k
    detail::const_stream_wrapper cs(p, end_);
833
58.1k
    BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
834
58.1k
    {
835
58.1k
        BOOST_ASSERT( literal >= 0 );
836
58.1k
        if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
837
57.8k
        {
838
57.8k
            int const cmp = std::memcmp(
839
57.8k
                cs.begin(), literals[literal], literal_sizes[literal] );
840
57.8k
            if( cmp != 0 )
841
124
            {
842
124
                BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
843
124
                return fail(cs.begin(), error::syntax, &loc);
844
124
            }
845
846
57.6k
            BOOST_IF_CONSTEXPR( literal == detail::null_literal )
847
13.6k
            {
848
13.6k
                if(BOOST_JSON_UNLIKELY(
849
13.6k
                    ! h_.on_null(ec_)))
850
0
                    return fail(cs.begin());
851
13.6k
            }
852
44.0k
            else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
853
22.4k
            {
854
22.4k
                if(BOOST_JSON_UNLIKELY(
855
22.4k
                    ! h_.on_bool(true, ec_)))
856
0
                    return fail(cs.begin());
857
22.4k
            }
858
21.6k
            else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
859
21.6k
            {
860
21.6k
                if(BOOST_JSON_UNLIKELY(
861
21.6k
                    ! h_.on_bool(false, ec_)))
862
0
                    return fail(cs.begin());
863
21.6k
            }
864
0
            else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
865
0
            {
866
0
                if(BOOST_JSON_UNLIKELY(
867
0
                    ! h_.on_double(
868
0
                        std::numeric_limits<double>::infinity(),
869
0
                        string_view(
870
0
                            literals[detail::infinity_literal],
871
0
                            literal_sizes[detail::infinity_literal]),
872
0
                        ec_)))
873
0
                    return fail(cs.begin());
874
0
            }
875
0
            else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
876
0
            {
877
0
                if(BOOST_JSON_UNLIKELY(
878
0
                    ! h_.on_double(
879
0
                        -std::numeric_limits<double>::infinity(),
880
0
                        string_view(
881
0
                            literals[detail::neg_infinity_literal],
882
0
                            literal_sizes[detail::neg_infinity_literal]),
883
0
                        ec_)))
884
0
                    return fail(cs.begin());
885
0
            }
886
0
            else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
887
0
            {
888
0
                if(BOOST_JSON_UNLIKELY(
889
0
                    ! h_.on_double(
890
0
                        std::numeric_limits<double>::quiet_NaN(),
891
0
                        string_view(
892
0
                            literals[detail::nan_literal],
893
0
                            literal_sizes[detail::nan_literal]),
894
0
                        ec_)))
895
0
                    return fail(cs.begin());
896
0
            }
897
0
            else
898
0
            {
899
0
                BOOST_JSON_UNREACHABLE();
900
0
            }
901
902
57.6k
            cs += literal_sizes[literal];
903
57.6k
            return cs.begin();
904
57.6k
        }
905
906
329
        offset = 0;
907
329
        cur_lit = literal;
908
329
    }
909
53
    else
910
53
    {
911
53
        state st;
912
53
        st_.pop(st);
913
53
        BOOST_ASSERT( st == state::lit1 );
914
915
53
        cur_lit = cur_lit_;
916
53
        offset = lit_offset_;
917
53
    }
918
919
382
    std::size_t const size = (std::min)(
920
382
        literal_sizes[cur_lit] - offset, cs.remain() );
921
382
    int cmp = 0;
922
382
    if(BOOST_JSON_LIKELY( cs.begin() ))
923
329
        cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
924
382
    if( cmp != 0 )
925
245
    {
926
245
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
927
245
        return fail(cs.begin(), error::syntax, &loc);
928
245
    }
929
930
137
    if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
931
137
    {
932
137
        BOOST_ASSERT( cur_lit < 256 );
933
137
        cur_lit_ = static_cast<unsigned char>( cur_lit );
934
137
        BOOST_ASSERT( offset + size < 256 );
935
137
        lit_offset_ = static_cast<unsigned char>( offset + size );
936
137
        return maybe_suspend(cs.begin() + size, state::lit1);
937
137
    }
938
939
0
    switch( cur_lit )
940
0
    {
941
0
    case detail::null_literal:
942
0
        if(BOOST_JSON_UNLIKELY(
943
0
            ! h_.on_null(ec_)))
944
0
            return fail(cs.begin());
945
0
        break;
946
0
    case detail::true_literal:
947
0
        if(BOOST_JSON_UNLIKELY(
948
0
            ! h_.on_bool(true, ec_)))
949
0
            return fail(cs.begin());
950
0
        break;
951
0
    case detail::false_literal:
952
0
        if(BOOST_JSON_UNLIKELY(
953
0
            ! h_.on_bool(false, ec_)))
954
0
            return fail(cs.begin());
955
0
        break;
956
0
    case detail::infinity_literal:
957
0
        if(BOOST_JSON_UNLIKELY(
958
0
            ! h_.on_double(
959
0
                std::numeric_limits<double>::infinity(),
960
0
                string_view(
961
0
                    literals[detail::infinity_literal],
962
0
                    literal_sizes[detail::infinity_literal]),
963
0
                ec_)))
964
0
            return fail(cs.begin());
965
0
        break;
966
0
    case detail::neg_infinity_literal:
967
0
        if(BOOST_JSON_UNLIKELY(
968
0
            ! h_.on_double(
969
0
                -std::numeric_limits<double>::infinity(),
970
0
                string_view(
971
0
                    literals[detail::neg_infinity_literal],
972
0
                    literal_sizes[detail::neg_infinity_literal]),
973
0
                ec_)))
974
0
            return fail(cs.begin());
975
0
        break;
976
0
    case detail::nan_literal:
977
0
        if(BOOST_JSON_UNLIKELY(
978
0
            ! h_.on_double(
979
0
                std::numeric_limits<double>::quiet_NaN(),
980
0
                string_view(
981
0
                    literals[detail::nan_literal],
982
0
                    literal_sizes[detail::nan_literal]),
983
0
                ec_)))
984
0
            return fail(cs.begin());
985
0
        break;
986
0
    default: BOOST_JSON_UNREACHABLE();
987
0
    }
988
989
0
    cs += size;
990
0
    return cs.begin();
991
0
}
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<4>(char const*, std::__1::integral_constant<int, 4>)
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<-1>(char const*, std::__1::integral_constant<int, -1>)
Line
Count
Source
810
53
{
811
53
    constexpr char const* literals[] = {
812
53
        "null",
813
53
        "true",
814
53
        "false",
815
53
        "Infinity",
816
53
        "-Infinity",
817
53
        "NaN",
818
53
    };
819
820
53
    constexpr std::size_t literal_sizes[] = {
821
53
        4,
822
53
        4,
823
53
        5,
824
53
        8,
825
53
        9,
826
53
        3,
827
53
    };
828
829
53
    std::size_t cur_lit;
830
53
    std::size_t offset;
831
832
53
    detail::const_stream_wrapper cs(p, end_);
833
53
    BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
834
0
    {
835
0
        BOOST_ASSERT( literal >= 0 );
836
0
        if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
837
0
        {
838
0
            int const cmp = std::memcmp(
839
0
                cs.begin(), literals[literal], literal_sizes[literal] );
840
0
            if( cmp != 0 )
841
0
            {
842
0
                BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
843
0
                return fail(cs.begin(), error::syntax, &loc);
844
0
            }
845
846
0
            BOOST_IF_CONSTEXPR( literal == detail::null_literal )
847
0
            {
848
0
                if(BOOST_JSON_UNLIKELY(
849
0
                    ! h_.on_null(ec_)))
850
0
                    return fail(cs.begin());
851
0
            }
852
0
            else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
853
0
            {
854
0
                if(BOOST_JSON_UNLIKELY(
855
0
                    ! h_.on_bool(true, ec_)))
856
0
                    return fail(cs.begin());
857
0
            }
858
0
            else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
859
0
            {
860
0
                if(BOOST_JSON_UNLIKELY(
861
0
                    ! h_.on_bool(false, ec_)))
862
0
                    return fail(cs.begin());
863
0
            }
864
0
            else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
865
0
            {
866
0
                if(BOOST_JSON_UNLIKELY(
867
0
                    ! h_.on_double(
868
0
                        std::numeric_limits<double>::infinity(),
869
0
                        string_view(
870
0
                            literals[detail::infinity_literal],
871
0
                            literal_sizes[detail::infinity_literal]),
872
0
                        ec_)))
873
0
                    return fail(cs.begin());
874
0
            }
875
0
            else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
876
0
            {
877
0
                if(BOOST_JSON_UNLIKELY(
878
0
                    ! h_.on_double(
879
0
                        -std::numeric_limits<double>::infinity(),
880
0
                        string_view(
881
0
                            literals[detail::neg_infinity_literal],
882
0
                            literal_sizes[detail::neg_infinity_literal]),
883
0
                        ec_)))
884
0
                    return fail(cs.begin());
885
0
            }
886
0
            else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
887
0
            {
888
0
                if(BOOST_JSON_UNLIKELY(
889
0
                    ! h_.on_double(
890
0
                        std::numeric_limits<double>::quiet_NaN(),
891
0
                        string_view(
892
0
                            literals[detail::nan_literal],
893
0
                            literal_sizes[detail::nan_literal]),
894
0
                        ec_)))
895
0
                    return fail(cs.begin());
896
0
            }
897
0
            else
898
0
            {
899
0
                BOOST_JSON_UNREACHABLE();
900
0
            }
901
902
0
            cs += literal_sizes[literal];
903
0
            return cs.begin();
904
0
        }
905
906
0
        offset = 0;
907
0
        cur_lit = literal;
908
0
    }
909
53
    else
910
53
    {
911
53
        state st;
912
53
        st_.pop(st);
913
53
        BOOST_ASSERT( st == state::lit1 );
914
915
53
        cur_lit = cur_lit_;
916
53
        offset = lit_offset_;
917
53
    }
918
919
53
    std::size_t const size = (std::min)(
920
53
        literal_sizes[cur_lit] - offset, cs.remain() );
921
53
    int cmp = 0;
922
53
    if(BOOST_JSON_LIKELY( cs.begin() ))
923
0
        cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
924
53
    if( cmp != 0 )
925
0
    {
926
0
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
927
0
        return fail(cs.begin(), error::syntax, &loc);
928
0
    }
929
930
53
    if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
931
53
    {
932
53
        BOOST_ASSERT( cur_lit < 256 );
933
53
        cur_lit_ = static_cast<unsigned char>( cur_lit );
934
53
        BOOST_ASSERT( offset + size < 256 );
935
53
        lit_offset_ = static_cast<unsigned char>( offset + size );
936
53
        return maybe_suspend(cs.begin() + size, state::lit1);
937
53
    }
938
939
0
    switch( cur_lit )
940
0
    {
941
0
    case detail::null_literal:
942
0
        if(BOOST_JSON_UNLIKELY(
943
0
            ! h_.on_null(ec_)))
944
0
            return fail(cs.begin());
945
0
        break;
946
0
    case detail::true_literal:
947
0
        if(BOOST_JSON_UNLIKELY(
948
0
            ! h_.on_bool(true, ec_)))
949
0
            return fail(cs.begin());
950
0
        break;
951
0
    case detail::false_literal:
952
0
        if(BOOST_JSON_UNLIKELY(
953
0
            ! h_.on_bool(false, ec_)))
954
0
            return fail(cs.begin());
955
0
        break;
956
0
    case detail::infinity_literal:
957
0
        if(BOOST_JSON_UNLIKELY(
958
0
            ! h_.on_double(
959
0
                std::numeric_limits<double>::infinity(),
960
0
                string_view(
961
0
                    literals[detail::infinity_literal],
962
0
                    literal_sizes[detail::infinity_literal]),
963
0
                ec_)))
964
0
            return fail(cs.begin());
965
0
        break;
966
0
    case detail::neg_infinity_literal:
967
0
        if(BOOST_JSON_UNLIKELY(
968
0
            ! h_.on_double(
969
0
                -std::numeric_limits<double>::infinity(),
970
0
                string_view(
971
0
                    literals[detail::neg_infinity_literal],
972
0
                    literal_sizes[detail::neg_infinity_literal]),
973
0
                ec_)))
974
0
            return fail(cs.begin());
975
0
        break;
976
0
    case detail::nan_literal:
977
0
        if(BOOST_JSON_UNLIKELY(
978
0
            ! h_.on_double(
979
0
                std::numeric_limits<double>::quiet_NaN(),
980
0
                string_view(
981
0
                    literals[detail::nan_literal],
982
0
                    literal_sizes[detail::nan_literal]),
983
0
                ec_)))
984
0
            return fail(cs.begin());
985
0
        break;
986
0
    default: BOOST_JSON_UNREACHABLE();
987
0
    }
988
989
0
    cs += size;
990
0
    return cs.begin();
991
0
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<0>(char const*, std::__1::integral_constant<int, 0>)
Line
Count
Source
810
13.7k
{
811
13.7k
    constexpr char const* literals[] = {
812
13.7k
        "null",
813
13.7k
        "true",
814
13.7k
        "false",
815
13.7k
        "Infinity",
816
13.7k
        "-Infinity",
817
13.7k
        "NaN",
818
13.7k
    };
819
820
13.7k
    constexpr std::size_t literal_sizes[] = {
821
13.7k
        4,
822
13.7k
        4,
823
13.7k
        5,
824
13.7k
        8,
825
13.7k
        9,
826
13.7k
        3,
827
13.7k
    };
828
829
13.7k
    std::size_t cur_lit;
830
13.7k
    std::size_t offset;
831
832
13.7k
    detail::const_stream_wrapper cs(p, end_);
833
13.7k
    BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
834
13.7k
    {
835
13.7k
        BOOST_ASSERT( literal >= 0 );
836
13.7k
        if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
837
13.6k
        {
838
13.6k
            int const cmp = std::memcmp(
839
13.6k
                cs.begin(), literals[literal], literal_sizes[literal] );
840
13.6k
            if( cmp != 0 )
841
35
            {
842
35
                BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
843
35
                return fail(cs.begin(), error::syntax, &loc);
844
35
            }
845
846
13.6k
            BOOST_IF_CONSTEXPR( literal == detail::null_literal )
847
13.6k
            {
848
13.6k
                if(BOOST_JSON_UNLIKELY(
849
13.6k
                    ! h_.on_null(ec_)))
850
0
                    return fail(cs.begin());
851
13.6k
            }
852
0
            else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
853
0
            {
854
0
                if(BOOST_JSON_UNLIKELY(
855
0
                    ! h_.on_bool(true, ec_)))
856
0
                    return fail(cs.begin());
857
0
            }
858
0
            else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
859
0
            {
860
0
                if(BOOST_JSON_UNLIKELY(
861
0
                    ! h_.on_bool(false, ec_)))
862
0
                    return fail(cs.begin());
863
0
            }
864
0
            else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
865
0
            {
866
0
                if(BOOST_JSON_UNLIKELY(
867
0
                    ! h_.on_double(
868
0
                        std::numeric_limits<double>::infinity(),
869
0
                        string_view(
870
0
                            literals[detail::infinity_literal],
871
0
                            literal_sizes[detail::infinity_literal]),
872
0
                        ec_)))
873
0
                    return fail(cs.begin());
874
0
            }
875
0
            else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
876
0
            {
877
0
                if(BOOST_JSON_UNLIKELY(
878
0
                    ! h_.on_double(
879
0
                        -std::numeric_limits<double>::infinity(),
880
0
                        string_view(
881
0
                            literals[detail::neg_infinity_literal],
882
0
                            literal_sizes[detail::neg_infinity_literal]),
883
0
                        ec_)))
884
0
                    return fail(cs.begin());
885
0
            }
886
0
            else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
887
0
            {
888
0
                if(BOOST_JSON_UNLIKELY(
889
0
                    ! h_.on_double(
890
0
                        std::numeric_limits<double>::quiet_NaN(),
891
0
                        string_view(
892
0
                            literals[detail::nan_literal],
893
0
                            literal_sizes[detail::nan_literal]),
894
0
                        ec_)))
895
0
                    return fail(cs.begin());
896
0
            }
897
0
            else
898
0
            {
899
0
                BOOST_JSON_UNREACHABLE();
900
0
            }
901
902
13.6k
            cs += literal_sizes[literal];
903
13.6k
            return cs.begin();
904
13.6k
        }
905
906
106
        offset = 0;
907
106
        cur_lit = literal;
908
106
    }
909
0
    else
910
0
    {
911
0
        state st;
912
0
        st_.pop(st);
913
0
        BOOST_ASSERT( st == state::lit1 );
914
915
0
        cur_lit = cur_lit_;
916
0
        offset = lit_offset_;
917
0
    }
918
919
106
    std::size_t const size = (std::min)(
920
106
        literal_sizes[cur_lit] - offset, cs.remain() );
921
106
    int cmp = 0;
922
106
    if(BOOST_JSON_LIKELY( cs.begin() ))
923
106
        cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
924
106
    if( cmp != 0 )
925
79
    {
926
79
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
927
79
        return fail(cs.begin(), error::syntax, &loc);
928
79
    }
929
930
27
    if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
931
27
    {
932
27
        BOOST_ASSERT( cur_lit < 256 );
933
27
        cur_lit_ = static_cast<unsigned char>( cur_lit );
934
27
        BOOST_ASSERT( offset + size < 256 );
935
27
        lit_offset_ = static_cast<unsigned char>( offset + size );
936
27
        return maybe_suspend(cs.begin() + size, state::lit1);
937
27
    }
938
939
0
    switch( cur_lit )
940
0
    {
941
0
    case detail::null_literal:
942
0
        if(BOOST_JSON_UNLIKELY(
943
0
            ! h_.on_null(ec_)))
944
0
            return fail(cs.begin());
945
0
        break;
946
0
    case detail::true_literal:
947
0
        if(BOOST_JSON_UNLIKELY(
948
0
            ! h_.on_bool(true, ec_)))
949
0
            return fail(cs.begin());
950
0
        break;
951
0
    case detail::false_literal:
952
0
        if(BOOST_JSON_UNLIKELY(
953
0
            ! h_.on_bool(false, ec_)))
954
0
            return fail(cs.begin());
955
0
        break;
956
0
    case detail::infinity_literal:
957
0
        if(BOOST_JSON_UNLIKELY(
958
0
            ! h_.on_double(
959
0
                std::numeric_limits<double>::infinity(),
960
0
                string_view(
961
0
                    literals[detail::infinity_literal],
962
0
                    literal_sizes[detail::infinity_literal]),
963
0
                ec_)))
964
0
            return fail(cs.begin());
965
0
        break;
966
0
    case detail::neg_infinity_literal:
967
0
        if(BOOST_JSON_UNLIKELY(
968
0
            ! h_.on_double(
969
0
                -std::numeric_limits<double>::infinity(),
970
0
                string_view(
971
0
                    literals[detail::neg_infinity_literal],
972
0
                    literal_sizes[detail::neg_infinity_literal]),
973
0
                ec_)))
974
0
            return fail(cs.begin());
975
0
        break;
976
0
    case detail::nan_literal:
977
0
        if(BOOST_JSON_UNLIKELY(
978
0
            ! h_.on_double(
979
0
                std::numeric_limits<double>::quiet_NaN(),
980
0
                string_view(
981
0
                    literals[detail::nan_literal],
982
0
                    literal_sizes[detail::nan_literal]),
983
0
                ec_)))
984
0
            return fail(cs.begin());
985
0
        break;
986
0
    default: BOOST_JSON_UNREACHABLE();
987
0
    }
988
989
0
    cs += size;
990
0
    return cs.begin();
991
0
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<1>(char const*, std::__1::integral_constant<int, 1>)
Line
Count
Source
810
22.5k
{
811
22.5k
    constexpr char const* literals[] = {
812
22.5k
        "null",
813
22.5k
        "true",
814
22.5k
        "false",
815
22.5k
        "Infinity",
816
22.5k
        "-Infinity",
817
22.5k
        "NaN",
818
22.5k
    };
819
820
22.5k
    constexpr std::size_t literal_sizes[] = {
821
22.5k
        4,
822
22.5k
        4,
823
22.5k
        5,
824
22.5k
        8,
825
22.5k
        9,
826
22.5k
        3,
827
22.5k
    };
828
829
22.5k
    std::size_t cur_lit;
830
22.5k
    std::size_t offset;
831
832
22.5k
    detail::const_stream_wrapper cs(p, end_);
833
22.5k
    BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
834
22.5k
    {
835
22.5k
        BOOST_ASSERT( literal >= 0 );
836
22.5k
        if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
837
22.4k
        {
838
22.4k
            int const cmp = std::memcmp(
839
22.4k
                cs.begin(), literals[literal], literal_sizes[literal] );
840
22.4k
            if( cmp != 0 )
841
37
            {
842
37
                BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
843
37
                return fail(cs.begin(), error::syntax, &loc);
844
37
            }
845
846
22.4k
            BOOST_IF_CONSTEXPR( literal == detail::null_literal )
847
0
            {
848
0
                if(BOOST_JSON_UNLIKELY(
849
0
                    ! h_.on_null(ec_)))
850
0
                    return fail(cs.begin());
851
0
            }
852
22.4k
            else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
853
22.4k
            {
854
22.4k
                if(BOOST_JSON_UNLIKELY(
855
22.4k
                    ! h_.on_bool(true, ec_)))
856
0
                    return fail(cs.begin());
857
22.4k
            }
858
0
            else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
859
0
            {
860
0
                if(BOOST_JSON_UNLIKELY(
861
0
                    ! h_.on_bool(false, ec_)))
862
0
                    return fail(cs.begin());
863
0
            }
864
0
            else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
865
0
            {
866
0
                if(BOOST_JSON_UNLIKELY(
867
0
                    ! h_.on_double(
868
0
                        std::numeric_limits<double>::infinity(),
869
0
                        string_view(
870
0
                            literals[detail::infinity_literal],
871
0
                            literal_sizes[detail::infinity_literal]),
872
0
                        ec_)))
873
0
                    return fail(cs.begin());
874
0
            }
875
0
            else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
876
0
            {
877
0
                if(BOOST_JSON_UNLIKELY(
878
0
                    ! h_.on_double(
879
0
                        -std::numeric_limits<double>::infinity(),
880
0
                        string_view(
881
0
                            literals[detail::neg_infinity_literal],
882
0
                            literal_sizes[detail::neg_infinity_literal]),
883
0
                        ec_)))
884
0
                    return fail(cs.begin());
885
0
            }
886
0
            else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
887
0
            {
888
0
                if(BOOST_JSON_UNLIKELY(
889
0
                    ! h_.on_double(
890
0
                        std::numeric_limits<double>::quiet_NaN(),
891
0
                        string_view(
892
0
                            literals[detail::nan_literal],
893
0
                            literal_sizes[detail::nan_literal]),
894
0
                        ec_)))
895
0
                    return fail(cs.begin());
896
0
            }
897
0
            else
898
0
            {
899
0
                BOOST_JSON_UNREACHABLE();
900
0
            }
901
902
22.4k
            cs += literal_sizes[literal];
903
22.4k
            return cs.begin();
904
22.4k
        }
905
906
106
        offset = 0;
907
106
        cur_lit = literal;
908
106
    }
909
0
    else
910
0
    {
911
0
        state st;
912
0
        st_.pop(st);
913
0
        BOOST_ASSERT( st == state::lit1 );
914
915
0
        cur_lit = cur_lit_;
916
0
        offset = lit_offset_;
917
0
    }
918
919
106
    std::size_t const size = (std::min)(
920
106
        literal_sizes[cur_lit] - offset, cs.remain() );
921
106
    int cmp = 0;
922
106
    if(BOOST_JSON_LIKELY( cs.begin() ))
923
106
        cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
924
106
    if( cmp != 0 )
925
78
    {
926
78
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
927
78
        return fail(cs.begin(), error::syntax, &loc);
928
78
    }
929
930
28
    if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
931
28
    {
932
28
        BOOST_ASSERT( cur_lit < 256 );
933
28
        cur_lit_ = static_cast<unsigned char>( cur_lit );
934
28
        BOOST_ASSERT( offset + size < 256 );
935
28
        lit_offset_ = static_cast<unsigned char>( offset + size );
936
28
        return maybe_suspend(cs.begin() + size, state::lit1);
937
28
    }
938
939
0
    switch( cur_lit )
940
0
    {
941
0
    case detail::null_literal:
942
0
        if(BOOST_JSON_UNLIKELY(
943
0
            ! h_.on_null(ec_)))
944
0
            return fail(cs.begin());
945
0
        break;
946
0
    case detail::true_literal:
947
0
        if(BOOST_JSON_UNLIKELY(
948
0
            ! h_.on_bool(true, ec_)))
949
0
            return fail(cs.begin());
950
0
        break;
951
0
    case detail::false_literal:
952
0
        if(BOOST_JSON_UNLIKELY(
953
0
            ! h_.on_bool(false, ec_)))
954
0
            return fail(cs.begin());
955
0
        break;
956
0
    case detail::infinity_literal:
957
0
        if(BOOST_JSON_UNLIKELY(
958
0
            ! h_.on_double(
959
0
                std::numeric_limits<double>::infinity(),
960
0
                string_view(
961
0
                    literals[detail::infinity_literal],
962
0
                    literal_sizes[detail::infinity_literal]),
963
0
                ec_)))
964
0
            return fail(cs.begin());
965
0
        break;
966
0
    case detail::neg_infinity_literal:
967
0
        if(BOOST_JSON_UNLIKELY(
968
0
            ! h_.on_double(
969
0
                -std::numeric_limits<double>::infinity(),
970
0
                string_view(
971
0
                    literals[detail::neg_infinity_literal],
972
0
                    literal_sizes[detail::neg_infinity_literal]),
973
0
                ec_)))
974
0
            return fail(cs.begin());
975
0
        break;
976
0
    case detail::nan_literal:
977
0
        if(BOOST_JSON_UNLIKELY(
978
0
            ! h_.on_double(
979
0
                std::numeric_limits<double>::quiet_NaN(),
980
0
                string_view(
981
0
                    literals[detail::nan_literal],
982
0
                    literal_sizes[detail::nan_literal]),
983
0
                ec_)))
984
0
            return fail(cs.begin());
985
0
        break;
986
0
    default: BOOST_JSON_UNREACHABLE();
987
0
    }
988
989
0
    cs += size;
990
0
    return cs.begin();
991
0
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<2>(char const*, std::__1::integral_constant<int, 2>)
Line
Count
Source
810
21.7k
{
811
21.7k
    constexpr char const* literals[] = {
812
21.7k
        "null",
813
21.7k
        "true",
814
21.7k
        "false",
815
21.7k
        "Infinity",
816
21.7k
        "-Infinity",
817
21.7k
        "NaN",
818
21.7k
    };
819
820
21.7k
    constexpr std::size_t literal_sizes[] = {
821
21.7k
        4,
822
21.7k
        4,
823
21.7k
        5,
824
21.7k
        8,
825
21.7k
        9,
826
21.7k
        3,
827
21.7k
    };
828
829
21.7k
    std::size_t cur_lit;
830
21.7k
    std::size_t offset;
831
832
21.7k
    detail::const_stream_wrapper cs(p, end_);
833
21.7k
    BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
834
21.7k
    {
835
21.7k
        BOOST_ASSERT( literal >= 0 );
836
21.7k
        if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
837
21.6k
        {
838
21.6k
            int const cmp = std::memcmp(
839
21.6k
                cs.begin(), literals[literal], literal_sizes[literal] );
840
21.6k
            if( cmp != 0 )
841
52
            {
842
52
                BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
843
52
                return fail(cs.begin(), error::syntax, &loc);
844
52
            }
845
846
21.6k
            BOOST_IF_CONSTEXPR( literal == detail::null_literal )
847
0
            {
848
0
                if(BOOST_JSON_UNLIKELY(
849
0
                    ! h_.on_null(ec_)))
850
0
                    return fail(cs.begin());
851
0
            }
852
21.6k
            else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
853
0
            {
854
0
                if(BOOST_JSON_UNLIKELY(
855
0
                    ! h_.on_bool(true, ec_)))
856
0
                    return fail(cs.begin());
857
0
            }
858
21.6k
            else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
859
21.6k
            {
860
21.6k
                if(BOOST_JSON_UNLIKELY(
861
21.6k
                    ! h_.on_bool(false, ec_)))
862
0
                    return fail(cs.begin());
863
21.6k
            }
864
0
            else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
865
0
            {
866
0
                if(BOOST_JSON_UNLIKELY(
867
0
                    ! h_.on_double(
868
0
                        std::numeric_limits<double>::infinity(),
869
0
                        string_view(
870
0
                            literals[detail::infinity_literal],
871
0
                            literal_sizes[detail::infinity_literal]),
872
0
                        ec_)))
873
0
                    return fail(cs.begin());
874
0
            }
875
0
            else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
876
0
            {
877
0
                if(BOOST_JSON_UNLIKELY(
878
0
                    ! h_.on_double(
879
0
                        -std::numeric_limits<double>::infinity(),
880
0
                        string_view(
881
0
                            literals[detail::neg_infinity_literal],
882
0
                            literal_sizes[detail::neg_infinity_literal]),
883
0
                        ec_)))
884
0
                    return fail(cs.begin());
885
0
            }
886
0
            else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
887
0
            {
888
0
                if(BOOST_JSON_UNLIKELY(
889
0
                    ! h_.on_double(
890
0
                        std::numeric_limits<double>::quiet_NaN(),
891
0
                        string_view(
892
0
                            literals[detail::nan_literal],
893
0
                            literal_sizes[detail::nan_literal]),
894
0
                        ec_)))
895
0
                    return fail(cs.begin());
896
0
            }
897
0
            else
898
0
            {
899
0
                BOOST_JSON_UNREACHABLE();
900
0
            }
901
902
21.6k
            cs += literal_sizes[literal];
903
21.6k
            return cs.begin();
904
21.6k
        }
905
906
117
        offset = 0;
907
117
        cur_lit = literal;
908
117
    }
909
0
    else
910
0
    {
911
0
        state st;
912
0
        st_.pop(st);
913
0
        BOOST_ASSERT( st == state::lit1 );
914
915
0
        cur_lit = cur_lit_;
916
0
        offset = lit_offset_;
917
0
    }
918
919
117
    std::size_t const size = (std::min)(
920
117
        literal_sizes[cur_lit] - offset, cs.remain() );
921
117
    int cmp = 0;
922
117
    if(BOOST_JSON_LIKELY( cs.begin() ))
923
117
        cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
924
117
    if( cmp != 0 )
925
88
    {
926
88
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
927
88
        return fail(cs.begin(), error::syntax, &loc);
928
88
    }
929
930
29
    if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
931
29
    {
932
29
        BOOST_ASSERT( cur_lit < 256 );
933
29
        cur_lit_ = static_cast<unsigned char>( cur_lit );
934
29
        BOOST_ASSERT( offset + size < 256 );
935
29
        lit_offset_ = static_cast<unsigned char>( offset + size );
936
29
        return maybe_suspend(cs.begin() + size, state::lit1);
937
29
    }
938
939
0
    switch( cur_lit )
940
0
    {
941
0
    case detail::null_literal:
942
0
        if(BOOST_JSON_UNLIKELY(
943
0
            ! h_.on_null(ec_)))
944
0
            return fail(cs.begin());
945
0
        break;
946
0
    case detail::true_literal:
947
0
        if(BOOST_JSON_UNLIKELY(
948
0
            ! h_.on_bool(true, ec_)))
949
0
            return fail(cs.begin());
950
0
        break;
951
0
    case detail::false_literal:
952
0
        if(BOOST_JSON_UNLIKELY(
953
0
            ! h_.on_bool(false, ec_)))
954
0
            return fail(cs.begin());
955
0
        break;
956
0
    case detail::infinity_literal:
957
0
        if(BOOST_JSON_UNLIKELY(
958
0
            ! h_.on_double(
959
0
                std::numeric_limits<double>::infinity(),
960
0
                string_view(
961
0
                    literals[detail::infinity_literal],
962
0
                    literal_sizes[detail::infinity_literal]),
963
0
                ec_)))
964
0
            return fail(cs.begin());
965
0
        break;
966
0
    case detail::neg_infinity_literal:
967
0
        if(BOOST_JSON_UNLIKELY(
968
0
            ! h_.on_double(
969
0
                -std::numeric_limits<double>::infinity(),
970
0
                string_view(
971
0
                    literals[detail::neg_infinity_literal],
972
0
                    literal_sizes[detail::neg_infinity_literal]),
973
0
                ec_)))
974
0
            return fail(cs.begin());
975
0
        break;
976
0
    case detail::nan_literal:
977
0
        if(BOOST_JSON_UNLIKELY(
978
0
            ! h_.on_double(
979
0
                std::numeric_limits<double>::quiet_NaN(),
980
0
                string_view(
981
0
                    literals[detail::nan_literal],
982
0
                    literal_sizes[detail::nan_literal]),
983
0
                ec_)))
984
0
            return fail(cs.begin());
985
0
        break;
986
0
    default: BOOST_JSON_UNREACHABLE();
987
0
    }
988
989
0
    cs += size;
990
0
    return cs.begin();
991
0
}
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<3>(char const*, std::__1::integral_constant<int, 3>)
Unexecuted instantiation: char const* boost::json::basic_parser<boost::json::detail::handler>::parse_literal<5>(char const*, std::__1::integral_constant<int, 5>)
992
993
//----------------------------------------------------------
994
995
template<class Handler>
996
template<
997
    bool StackEmpty_,
998
    bool IsKey_/*,
999
    bool AllowBadUTF8_*/>
1000
const char*
1001
basic_parser<Handler>::
1002
parse_string(const char* p,
1003
    std::integral_constant<bool, StackEmpty_> stack_empty,
1004
    std::integral_constant<bool, IsKey_> is_key,
1005
    /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8)
1006
991k
{
1007
991k
    if(! stack_empty && ! st_.empty())
1008
223
    {
1009
223
        state st;
1010
223
        st_.peek(st);
1011
223
        switch(st)
1012
223
        {
1013
0
        default: BOOST_JSON_UNREACHABLE();
1014
139
        case state::str1:
1015
139
            return parse_unescaped(p, stack_empty, is_key, allow_bad_utf8);
1016
1017
57
        case state::str2: case state::str3:
1018
58
        case state::str4: case state::str5:
1019
61
        case state::str6: case state::str7:
1020
78
        case state::str8:
1021
79
        case state::sur1: case state::sur2:
1022
79
        case state::sur3: case state::sur4:
1023
84
        case state::sur5: case state::sur6:
1024
84
            return parse_escaped(p, 0, stack_empty, is_key, allow_bad_utf8);
1025
223
        }
1026
223
    }
1027
1028
991k
    return parse_unescaped(p, std::true_type(), is_key, allow_bad_utf8);
1029
991k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_string<true, true>(char const*, std::__1::integral_constant<bool, true>, std::__1::integral_constant<bool, true>, bool)
Line
Count
Source
1006
991k
{
1007
991k
    if(! stack_empty && ! st_.empty())
1008
0
    {
1009
0
        state st;
1010
0
        st_.peek(st);
1011
0
        switch(st)
1012
0
        {
1013
0
        default: BOOST_JSON_UNREACHABLE();
1014
0
        case state::str1:
1015
0
            return parse_unescaped(p, stack_empty, is_key, allow_bad_utf8);
1016
1017
0
        case state::str2: case state::str3:
1018
0
        case state::str4: case state::str5:
1019
0
        case state::str6: case state::str7:
1020
0
        case state::str8:
1021
0
        case state::sur1: case state::sur2:
1022
0
        case state::sur3: case state::sur4:
1023
0
        case state::sur5: case state::sur6:
1024
0
            return parse_escaped(p, 0, stack_empty, is_key, allow_bad_utf8);
1025
0
        }
1026
0
    }
1027
1028
991k
    return parse_unescaped(p, std::true_type(), is_key, allow_bad_utf8);
1029
991k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_string<false, true>(char const*, std::__1::integral_constant<bool, false>, std::__1::integral_constant<bool, true>, bool)
Line
Count
Source
1006
223
{
1007
223
    if(! stack_empty && ! st_.empty())
1008
223
    {
1009
223
        state st;
1010
223
        st_.peek(st);
1011
223
        switch(st)
1012
223
        {
1013
0
        default: BOOST_JSON_UNREACHABLE();
1014
139
        case state::str1:
1015
139
            return parse_unescaped(p, stack_empty, is_key, allow_bad_utf8);
1016
1017
57
        case state::str2: case state::str3:
1018
58
        case state::str4: case state::str5:
1019
61
        case state::str6: case state::str7:
1020
78
        case state::str8:
1021
79
        case state::sur1: case state::sur2:
1022
79
        case state::sur3: case state::sur4:
1023
84
        case state::sur5: case state::sur6:
1024
84
            return parse_escaped(p, 0, stack_empty, is_key, allow_bad_utf8);
1025
223
        }
1026
223
    }
1027
1028
0
    return parse_unescaped(p, std::true_type(), is_key, allow_bad_utf8);
1029
223
}
1030
1031
template<class Handler>
1032
template<
1033
    bool StackEmpty_,
1034
    bool IsKey_/*,
1035
    bool AllowBadUTF8_*/>
1036
const char*
1037
basic_parser<Handler>::
1038
parse_unescaped(const char* p,
1039
    std::integral_constant<bool, StackEmpty_> stack_empty,
1040
    std::integral_constant<bool, IsKey_> is_key,
1041
    /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8)
1042
1.07M
{
1043
1.07M
    detail::const_stream_wrapper cs(p, end_);
1044
1.07M
    std::size_t total;
1045
1.07M
    if(stack_empty || st_.empty())
1046
1.07M
    {
1047
1.07M
        BOOST_ASSERT(*cs == '\x22'); // '"'
1048
1.07M
        ++cs;
1049
1.07M
        total = 0;
1050
1.07M
    }
1051
294
    else
1052
294
    {
1053
294
        state st;
1054
294
        st_.pop(st);
1055
294
        st_.pop(total);
1056
294
    }
1057
1.07M
    char const* start = cs.begin();
1058
1.07M
    cs = allow_bad_utf8?
1059
190k
        detail::count_valid<true>(cs.begin(), cs.end()):
1060
1.07M
        detail::count_valid<false>(cs.begin(), cs.end());
1061
1.07M
    std::size_t size = cs.used(start);
1062
1.07M
    if(is_key)
1063
991k
    {
1064
991k
        BOOST_ASSERT(total <= Handler::max_key_size);
1065
991k
        if(BOOST_JSON_UNLIKELY(size >
1066
991k
            Handler::max_key_size - total))
1067
0
        {
1068
0
            BOOST_STATIC_CONSTEXPR source_location loc
1069
0
                = BOOST_CURRENT_LOCATION;
1070
0
            return fail(cs.begin(), error::key_too_large, &loc);
1071
0
        }
1072
991k
    }
1073
82.5k
    else
1074
82.5k
    {
1075
82.5k
        BOOST_ASSERT(total <= Handler::max_string_size);
1076
82.5k
        if(BOOST_JSON_UNLIKELY(size >
1077
82.5k
            Handler::max_string_size - total))
1078
0
        {
1079
0
            BOOST_STATIC_CONSTEXPR source_location loc
1080
0
                = BOOST_CURRENT_LOCATION;
1081
0
            return fail(cs.begin(), error::string_too_large, &loc);
1082
0
        }
1083
82.5k
    }
1084
1.07M
    total += size;
1085
1.07M
    if(BOOST_JSON_UNLIKELY(! cs))
1086
860
    {
1087
        // call handler if the string isn't empty
1088
860
        if(BOOST_JSON_LIKELY(size))
1089
479
        {
1090
479
            {
1091
479
                bool r = is_key?
1092
203
                    h_.on_key_part( {start, size}, total, ec_ ):
1093
479
                    h_.on_string_part( {start, size}, total, ec_ );
1094
1095
479
                if(BOOST_JSON_UNLIKELY(!r))
1096
0
                {
1097
0
                    return fail(cs.begin());
1098
0
                }
1099
479
            }
1100
479
        }
1101
860
        return maybe_suspend(cs.begin(), state::str1, total);
1102
860
    }
1103
    // at this point all valid characters have been skipped, so any remaining
1104
    // if there are any more characters, they are either escaped, or incomplete
1105
    // utf8, or invalid utf8
1106
1.07M
    if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1107
47.1k
    {
1108
        // sequence is invalid or incomplete
1109
47.1k
        if((*cs & 0x80) && !allow_bad_utf8)
1110
555
        {
1111
555
            seq_.save(cs.begin(), cs.remain());
1112
555
            if(BOOST_JSON_UNLIKELY(seq_.complete()))
1113
454
            {
1114
454
                BOOST_STATIC_CONSTEXPR source_location loc
1115
454
                    = BOOST_CURRENT_LOCATION;
1116
454
                return fail(cs.begin(), error::syntax, &loc);
1117
454
            }
1118
101
            if(BOOST_JSON_LIKELY(size))
1119
73
            {
1120
73
                {
1121
73
                    bool r = is_key?
1122
30
                        h_.on_key_part( {start, size}, total, ec_ ):
1123
73
                        h_.on_string_part( {start, size}, total, ec_ );
1124
1125
73
                    if(BOOST_JSON_UNLIKELY(!r))
1126
0
                    {
1127
0
                        return fail(cs.begin());
1128
0
                    }
1129
73
                }
1130
73
            }
1131
101
            return maybe_suspend(cs.end(), state::str8, total);
1132
101
        }
1133
46.6k
        else if(BOOST_JSON_LIKELY(*cs == '\\'))
1134
46.5k
        {
1135
            // flush unescaped run from input
1136
46.5k
            if(BOOST_JSON_LIKELY(size))
1137
22.5k
            {
1138
22.5k
                {
1139
22.5k
                    bool r = is_key?
1140
3.58k
                        h_.on_key_part( {start, size}, total, ec_ ):
1141
22.5k
                        h_.on_string_part( {start, size}, total, ec_ );
1142
1143
22.5k
                    if(BOOST_JSON_UNLIKELY(!r))
1144
0
                    {
1145
0
                        return fail(cs.begin());
1146
0
                    }
1147
22.5k
                }
1148
22.5k
            }
1149
46.5k
            return parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf8);
1150
46.5k
        }
1151
        // illegal control
1152
83
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1153
83
        return fail(cs.begin(), error::syntax, &loc);
1154
47.1k
    }
1155
1156
1.02M
    {
1157
1.02M
        bool r = is_key?
1158
985k
            h_.on_key( {start, size}, total, ec_ ):
1159
1.02M
            h_.on_string( {start, size}, total, ec_ );
1160
1161
1.02M
        if(BOOST_JSON_UNLIKELY(!r))
1162
0
        {
1163
0
            return fail(cs.begin());
1164
0
        }
1165
1.02M
    }
1166
1167
1.02M
    ++cs;
1168
1.02M
    return cs.begin();
1169
1.02M
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_unescaped<true, false>(char const*, std::__1::integral_constant<bool, true>, std::__1::integral_constant<bool, false>, bool)
Line
Count
Source
1042
82.4k
{
1043
82.4k
    detail::const_stream_wrapper cs(p, end_);
1044
82.4k
    std::size_t total;
1045
82.4k
    if(stack_empty || st_.empty())
1046
82.4k
    {
1047
82.4k
        BOOST_ASSERT(*cs == '\x22'); // '"'
1048
82.4k
        ++cs;
1049
82.4k
        total = 0;
1050
82.4k
    }
1051
0
    else
1052
0
    {
1053
0
        state st;
1054
0
        st_.pop(st);
1055
0
        st_.pop(total);
1056
0
    }
1057
82.4k
    char const* start = cs.begin();
1058
82.4k
    cs = allow_bad_utf8?
1059
32.7k
        detail::count_valid<true>(cs.begin(), cs.end()):
1060
82.4k
        detail::count_valid<false>(cs.begin(), cs.end());
1061
82.4k
    std::size_t size = cs.used(start);
1062
82.4k
    if(is_key)
1063
0
    {
1064
0
        BOOST_ASSERT(total <= Handler::max_key_size);
1065
0
        if(BOOST_JSON_UNLIKELY(size >
1066
0
            Handler::max_key_size - total))
1067
0
        {
1068
0
            BOOST_STATIC_CONSTEXPR source_location loc
1069
0
                = BOOST_CURRENT_LOCATION;
1070
0
            return fail(cs.begin(), error::key_too_large, &loc);
1071
0
        }
1072
0
    }
1073
82.4k
    else
1074
82.4k
    {
1075
82.4k
        BOOST_ASSERT(total <= Handler::max_string_size);
1076
82.4k
        if(BOOST_JSON_UNLIKELY(size >
1077
82.4k
            Handler::max_string_size - total))
1078
0
        {
1079
0
            BOOST_STATIC_CONSTEXPR source_location loc
1080
0
                = BOOST_CURRENT_LOCATION;
1081
0
            return fail(cs.begin(), error::string_too_large, &loc);
1082
0
        }
1083
82.4k
    }
1084
82.4k
    total += size;
1085
82.4k
    if(BOOST_JSON_UNLIKELY(! cs))
1086
313
    {
1087
        // call handler if the string isn't empty
1088
313
        if(BOOST_JSON_LIKELY(size))
1089
276
        {
1090
276
            {
1091
276
                bool r = is_key?
1092
0
                    h_.on_key_part( {start, size}, total, ec_ ):
1093
276
                    h_.on_string_part( {start, size}, total, ec_ );
1094
1095
276
                if(BOOST_JSON_UNLIKELY(!r))
1096
0
                {
1097
0
                    return fail(cs.begin());
1098
0
                }
1099
276
            }
1100
276
        }
1101
313
        return maybe_suspend(cs.begin(), state::str1, total);
1102
313
    }
1103
    // at this point all valid characters have been skipped, so any remaining
1104
    // if there are any more characters, they are either escaped, or incomplete
1105
    // utf8, or invalid utf8
1106
82.1k
    if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1107
41.5k
    {
1108
        // sequence is invalid or incomplete
1109
41.5k
        if((*cs & 0x80) && !allow_bad_utf8)
1110
294
        {
1111
294
            seq_.save(cs.begin(), cs.remain());
1112
294
            if(BOOST_JSON_UNLIKELY(seq_.complete()))
1113
235
            {
1114
235
                BOOST_STATIC_CONSTEXPR source_location loc
1115
235
                    = BOOST_CURRENT_LOCATION;
1116
235
                return fail(cs.begin(), error::syntax, &loc);
1117
235
            }
1118
59
            if(BOOST_JSON_LIKELY(size))
1119
43
            {
1120
43
                {
1121
43
                    bool r = is_key?
1122
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1123
43
                        h_.on_string_part( {start, size}, total, ec_ );
1124
1125
43
                    if(BOOST_JSON_UNLIKELY(!r))
1126
0
                    {
1127
0
                        return fail(cs.begin());
1128
0
                    }
1129
43
                }
1130
43
            }
1131
59
            return maybe_suspend(cs.end(), state::str8, total);
1132
59
        }
1133
41.2k
        else if(BOOST_JSON_LIKELY(*cs == '\\'))
1134
41.2k
        {
1135
            // flush unescaped run from input
1136
41.2k
            if(BOOST_JSON_LIKELY(size))
1137
18.9k
            {
1138
18.9k
                {
1139
18.9k
                    bool r = is_key?
1140
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1141
18.9k
                        h_.on_string_part( {start, size}, total, ec_ );
1142
1143
18.9k
                    if(BOOST_JSON_UNLIKELY(!r))
1144
0
                    {
1145
0
                        return fail(cs.begin());
1146
0
                    }
1147
18.9k
                }
1148
18.9k
            }
1149
41.2k
            return parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf8);
1150
41.2k
        }
1151
        // illegal control
1152
42
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1153
42
        return fail(cs.begin(), error::syntax, &loc);
1154
41.5k
    }
1155
1156
40.5k
    {
1157
40.5k
        bool r = is_key?
1158
0
            h_.on_key( {start, size}, total, ec_ ):
1159
40.5k
            h_.on_string( {start, size}, total, ec_ );
1160
1161
40.5k
        if(BOOST_JSON_UNLIKELY(!r))
1162
0
        {
1163
0
            return fail(cs.begin());
1164
0
        }
1165
40.5k
    }
1166
1167
40.5k
    ++cs;
1168
40.5k
    return cs.begin();
1169
40.5k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_unescaped<true, true>(char const*, std::__1::integral_constant<bool, true>, std::__1::integral_constant<bool, true>, bool)
Line
Count
Source
1042
991k
{
1043
991k
    detail::const_stream_wrapper cs(p, end_);
1044
991k
    std::size_t total;
1045
991k
    if(stack_empty || st_.empty())
1046
991k
    {
1047
991k
        BOOST_ASSERT(*cs == '\x22'); // '"'
1048
991k
        ++cs;
1049
991k
        total = 0;
1050
991k
    }
1051
0
    else
1052
0
    {
1053
0
        state st;
1054
0
        st_.pop(st);
1055
0
        st_.pop(total);
1056
0
    }
1057
991k
    char const* start = cs.begin();
1058
991k
    cs = allow_bad_utf8?
1059
157k
        detail::count_valid<true>(cs.begin(), cs.end()):
1060
991k
        detail::count_valid<false>(cs.begin(), cs.end());
1061
991k
    std::size_t size = cs.used(start);
1062
991k
    if(is_key)
1063
991k
    {
1064
991k
        BOOST_ASSERT(total <= Handler::max_key_size);
1065
991k
        if(BOOST_JSON_UNLIKELY(size >
1066
991k
            Handler::max_key_size - total))
1067
0
        {
1068
0
            BOOST_STATIC_CONSTEXPR source_location loc
1069
0
                = BOOST_CURRENT_LOCATION;
1070
0
            return fail(cs.begin(), error::key_too_large, &loc);
1071
0
        }
1072
991k
    }
1073
0
    else
1074
0
    {
1075
0
        BOOST_ASSERT(total <= Handler::max_string_size);
1076
0
        if(BOOST_JSON_UNLIKELY(size >
1077
0
            Handler::max_string_size - total))
1078
0
        {
1079
0
            BOOST_STATIC_CONSTEXPR source_location loc
1080
0
                = BOOST_CURRENT_LOCATION;
1081
0
            return fail(cs.begin(), error::string_too_large, &loc);
1082
0
        }
1083
0
    }
1084
991k
    total += size;
1085
991k
    if(BOOST_JSON_UNLIKELY(! cs))
1086
253
    {
1087
        // call handler if the string isn't empty
1088
253
        if(BOOST_JSON_LIKELY(size))
1089
203
        {
1090
203
            {
1091
203
                bool r = is_key?
1092
203
                    h_.on_key_part( {start, size}, total, ec_ ):
1093
203
                    h_.on_string_part( {start, size}, total, ec_ );
1094
1095
203
                if(BOOST_JSON_UNLIKELY(!r))
1096
0
                {
1097
0
                    return fail(cs.begin());
1098
0
                }
1099
203
            }
1100
203
        }
1101
253
        return maybe_suspend(cs.begin(), state::str1, total);
1102
253
    }
1103
    // at this point all valid characters have been skipped, so any remaining
1104
    // if there are any more characters, they are either escaped, or incomplete
1105
    // utf8, or invalid utf8
1106
991k
    if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1107
5.61k
    {
1108
        // sequence is invalid or incomplete
1109
5.61k
        if((*cs & 0x80) && !allow_bad_utf8)
1110
261
        {
1111
261
            seq_.save(cs.begin(), cs.remain());
1112
261
            if(BOOST_JSON_UNLIKELY(seq_.complete()))
1113
219
            {
1114
219
                BOOST_STATIC_CONSTEXPR source_location loc
1115
219
                    = BOOST_CURRENT_LOCATION;
1116
219
                return fail(cs.begin(), error::syntax, &loc);
1117
219
            }
1118
42
            if(BOOST_JSON_LIKELY(size))
1119
30
            {
1120
30
                {
1121
30
                    bool r = is_key?
1122
30
                        h_.on_key_part( {start, size}, total, ec_ ):
1123
30
                        h_.on_string_part( {start, size}, total, ec_ );
1124
1125
30
                    if(BOOST_JSON_UNLIKELY(!r))
1126
0
                    {
1127
0
                        return fail(cs.begin());
1128
0
                    }
1129
30
                }
1130
30
            }
1131
42
            return maybe_suspend(cs.end(), state::str8, total);
1132
42
        }
1133
5.35k
        else if(BOOST_JSON_LIKELY(*cs == '\\'))
1134
5.30k
        {
1135
            // flush unescaped run from input
1136
5.30k
            if(BOOST_JSON_LIKELY(size))
1137
3.58k
            {
1138
3.58k
                {
1139
3.58k
                    bool r = is_key?
1140
3.58k
                        h_.on_key_part( {start, size}, total, ec_ ):
1141
3.58k
                        h_.on_string_part( {start, size}, total, ec_ );
1142
1143
3.58k
                    if(BOOST_JSON_UNLIKELY(!r))
1144
0
                    {
1145
0
                        return fail(cs.begin());
1146
0
                    }
1147
3.58k
                }
1148
3.58k
            }
1149
5.30k
            return parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf8);
1150
5.30k
        }
1151
        // illegal control
1152
41
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1153
41
        return fail(cs.begin(), error::syntax, &loc);
1154
5.61k
    }
1155
1156
985k
    {
1157
985k
        bool r = is_key?
1158
985k
            h_.on_key( {start, size}, total, ec_ ):
1159
985k
            h_.on_string( {start, size}, total, ec_ );
1160
1161
985k
        if(BOOST_JSON_UNLIKELY(!r))
1162
0
        {
1163
0
            return fail(cs.begin());
1164
0
        }
1165
985k
    }
1166
1167
985k
    ++cs;
1168
985k
    return cs.begin();
1169
985k
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_unescaped<false, false>(char const*, std::__1::integral_constant<bool, false>, std::__1::integral_constant<bool, false>, bool)
Line
Count
Source
1042
155
{
1043
155
    detail::const_stream_wrapper cs(p, end_);
1044
155
    std::size_t total;
1045
155
    if(stack_empty || st_.empty())
1046
0
    {
1047
0
        BOOST_ASSERT(*cs == '\x22'); // '"'
1048
0
        ++cs;
1049
0
        total = 0;
1050
0
    }
1051
155
    else
1052
155
    {
1053
155
        state st;
1054
155
        st_.pop(st);
1055
155
        st_.pop(total);
1056
155
    }
1057
155
    char const* start = cs.begin();
1058
155
    cs = allow_bad_utf8?
1059
77
        detail::count_valid<true>(cs.begin(), cs.end()):
1060
155
        detail::count_valid<false>(cs.begin(), cs.end());
1061
155
    std::size_t size = cs.used(start);
1062
155
    if(is_key)
1063
0
    {
1064
0
        BOOST_ASSERT(total <= Handler::max_key_size);
1065
0
        if(BOOST_JSON_UNLIKELY(size >
1066
0
            Handler::max_key_size - total))
1067
0
        {
1068
0
            BOOST_STATIC_CONSTEXPR source_location loc
1069
0
                = BOOST_CURRENT_LOCATION;
1070
0
            return fail(cs.begin(), error::key_too_large, &loc);
1071
0
        }
1072
0
    }
1073
155
    else
1074
155
    {
1075
155
        BOOST_ASSERT(total <= Handler::max_string_size);
1076
155
        if(BOOST_JSON_UNLIKELY(size >
1077
155
            Handler::max_string_size - total))
1078
0
        {
1079
0
            BOOST_STATIC_CONSTEXPR source_location loc
1080
0
                = BOOST_CURRENT_LOCATION;
1081
0
            return fail(cs.begin(), error::string_too_large, &loc);
1082
0
        }
1083
155
    }
1084
155
    total += size;
1085
155
    if(BOOST_JSON_UNLIKELY(! cs))
1086
155
    {
1087
        // call handler if the string isn't empty
1088
155
        if(BOOST_JSON_LIKELY(size))
1089
0
        {
1090
0
            {
1091
0
                bool r = is_key?
1092
0
                    h_.on_key_part( {start, size}, total, ec_ ):
1093
0
                    h_.on_string_part( {start, size}, total, ec_ );
1094
1095
0
                if(BOOST_JSON_UNLIKELY(!r))
1096
0
                {
1097
0
                    return fail(cs.begin());
1098
0
                }
1099
0
            }
1100
0
        }
1101
155
        return maybe_suspend(cs.begin(), state::str1, total);
1102
155
    }
1103
    // at this point all valid characters have been skipped, so any remaining
1104
    // if there are any more characters, they are either escaped, or incomplete
1105
    // utf8, or invalid utf8
1106
0
    if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1107
0
    {
1108
        // sequence is invalid or incomplete
1109
0
        if((*cs & 0x80) && !allow_bad_utf8)
1110
0
        {
1111
0
            seq_.save(cs.begin(), cs.remain());
1112
0
            if(BOOST_JSON_UNLIKELY(seq_.complete()))
1113
0
            {
1114
0
                BOOST_STATIC_CONSTEXPR source_location loc
1115
0
                    = BOOST_CURRENT_LOCATION;
1116
0
                return fail(cs.begin(), error::syntax, &loc);
1117
0
            }
1118
0
            if(BOOST_JSON_LIKELY(size))
1119
0
            {
1120
0
                {
1121
0
                    bool r = is_key?
1122
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1123
0
                        h_.on_string_part( {start, size}, total, ec_ );
1124
1125
0
                    if(BOOST_JSON_UNLIKELY(!r))
1126
0
                    {
1127
0
                        return fail(cs.begin());
1128
0
                    }
1129
0
                }
1130
0
            }
1131
0
            return maybe_suspend(cs.end(), state::str8, total);
1132
0
        }
1133
0
        else if(BOOST_JSON_LIKELY(*cs == '\\'))
1134
0
        {
1135
            // flush unescaped run from input
1136
0
            if(BOOST_JSON_LIKELY(size))
1137
0
            {
1138
0
                {
1139
0
                    bool r = is_key?
1140
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1141
0
                        h_.on_string_part( {start, size}, total, ec_ );
1142
1143
0
                    if(BOOST_JSON_UNLIKELY(!r))
1144
0
                    {
1145
0
                        return fail(cs.begin());
1146
0
                    }
1147
0
                }
1148
0
            }
1149
0
            return parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf8);
1150
0
        }
1151
        // illegal control
1152
0
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1153
0
        return fail(cs.begin(), error::syntax, &loc);
1154
0
    }
1155
1156
0
    {
1157
0
        bool r = is_key?
1158
0
            h_.on_key( {start, size}, total, ec_ ):
1159
0
            h_.on_string( {start, size}, total, ec_ );
1160
1161
0
        if(BOOST_JSON_UNLIKELY(!r))
1162
0
        {
1163
0
            return fail(cs.begin());
1164
0
        }
1165
0
    }
1166
1167
0
    ++cs;
1168
0
    return cs.begin();
1169
0
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_unescaped<false, true>(char const*, std::__1::integral_constant<bool, false>, std::__1::integral_constant<bool, true>, bool)
Line
Count
Source
1042
139
{
1043
139
    detail::const_stream_wrapper cs(p, end_);
1044
139
    std::size_t total;
1045
139
    if(stack_empty || st_.empty())
1046
0
    {
1047
0
        BOOST_ASSERT(*cs == '\x22'); // '"'
1048
0
        ++cs;
1049
0
        total = 0;
1050
0
    }
1051
139
    else
1052
139
    {
1053
139
        state st;
1054
139
        st_.pop(st);
1055
139
        st_.pop(total);
1056
139
    }
1057
139
    char const* start = cs.begin();
1058
139
    cs = allow_bad_utf8?
1059
63
        detail::count_valid<true>(cs.begin(), cs.end()):
1060
139
        detail::count_valid<false>(cs.begin(), cs.end());
1061
139
    std::size_t size = cs.used(start);
1062
139
    if(is_key)
1063
139
    {
1064
139
        BOOST_ASSERT(total <= Handler::max_key_size);
1065
139
        if(BOOST_JSON_UNLIKELY(size >
1066
139
            Handler::max_key_size - total))
1067
0
        {
1068
0
            BOOST_STATIC_CONSTEXPR source_location loc
1069
0
                = BOOST_CURRENT_LOCATION;
1070
0
            return fail(cs.begin(), error::key_too_large, &loc);
1071
0
        }
1072
139
    }
1073
0
    else
1074
0
    {
1075
0
        BOOST_ASSERT(total <= Handler::max_string_size);
1076
0
        if(BOOST_JSON_UNLIKELY(size >
1077
0
            Handler::max_string_size - total))
1078
0
        {
1079
0
            BOOST_STATIC_CONSTEXPR source_location loc
1080
0
                = BOOST_CURRENT_LOCATION;
1081
0
            return fail(cs.begin(), error::string_too_large, &loc);
1082
0
        }
1083
0
    }
1084
139
    total += size;
1085
139
    if(BOOST_JSON_UNLIKELY(! cs))
1086
139
    {
1087
        // call handler if the string isn't empty
1088
139
        if(BOOST_JSON_LIKELY(size))
1089
0
        {
1090
0
            {
1091
0
                bool r = is_key?
1092
0
                    h_.on_key_part( {start, size}, total, ec_ ):
1093
0
                    h_.on_string_part( {start, size}, total, ec_ );
1094
1095
0
                if(BOOST_JSON_UNLIKELY(!r))
1096
0
                {
1097
0
                    return fail(cs.begin());
1098
0
                }
1099
0
            }
1100
0
        }
1101
139
        return maybe_suspend(cs.begin(), state::str1, total);
1102
139
    }
1103
    // at this point all valid characters have been skipped, so any remaining
1104
    // if there are any more characters, they are either escaped, or incomplete
1105
    // utf8, or invalid utf8
1106
0
    if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1107
0
    {
1108
        // sequence is invalid or incomplete
1109
0
        if((*cs & 0x80) && !allow_bad_utf8)
1110
0
        {
1111
0
            seq_.save(cs.begin(), cs.remain());
1112
0
            if(BOOST_JSON_UNLIKELY(seq_.complete()))
1113
0
            {
1114
0
                BOOST_STATIC_CONSTEXPR source_location loc
1115
0
                    = BOOST_CURRENT_LOCATION;
1116
0
                return fail(cs.begin(), error::syntax, &loc);
1117
0
            }
1118
0
            if(BOOST_JSON_LIKELY(size))
1119
0
            {
1120
0
                {
1121
0
                    bool r = is_key?
1122
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1123
0
                        h_.on_string_part( {start, size}, total, ec_ );
1124
1125
0
                    if(BOOST_JSON_UNLIKELY(!r))
1126
0
                    {
1127
0
                        return fail(cs.begin());
1128
0
                    }
1129
0
                }
1130
0
            }
1131
0
            return maybe_suspend(cs.end(), state::str8, total);
1132
0
        }
1133
0
        else if(BOOST_JSON_LIKELY(*cs == '\\'))
1134
0
        {
1135
            // flush unescaped run from input
1136
0
            if(BOOST_JSON_LIKELY(size))
1137
0
            {
1138
0
                {
1139
0
                    bool r = is_key?
1140
0
                        h_.on_key_part( {start, size}, total, ec_ ):
1141
0
                        h_.on_string_part( {start, size}, total, ec_ );
1142
1143
0
                    if(BOOST_JSON_UNLIKELY(!r))
1144
0
                    {
1145
0
                        return fail(cs.begin());
1146
0
                    }
1147
0
                }
1148
0
            }
1149
0
            return parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf8);
1150
0
        }
1151
        // illegal control
1152
0
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1153
0
        return fail(cs.begin(), error::syntax, &loc);
1154
0
    }
1155
1156
0
    {
1157
0
        bool r = is_key?
1158
0
            h_.on_key( {start, size}, total, ec_ ):
1159
0
            h_.on_string( {start, size}, total, ec_ );
1160
1161
0
        if(BOOST_JSON_UNLIKELY(!r))
1162
0
        {
1163
0
            return fail(cs.begin());
1164
0
        }
1165
0
    }
1166
1167
0
    ++cs;
1168
0
    return cs.begin();
1169
0
}
1170
1171
template<class Handler>
1172
template<
1173
    bool StackEmpty_/*,
1174
    bool IsKey_,
1175
    bool AllowBadUTF8_*/>
1176
const char*
1177
basic_parser<Handler>::
1178
parse_escaped(
1179
    const char* p,
1180
    std::size_t total,
1181
    std::integral_constant<bool, StackEmpty_> stack_empty,
1182
    /*std::integral_constant<bool, IsKey_>*/ bool is_key,
1183
    /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8)
1184
47.1k
{
1185
    //---------------------------------------------------------------
1186
    //
1187
    // To handle escapes, a local temporary buffer accumulates
1188
    // the unescaped result. The algorithm attempts to fill the
1189
    // buffer to capacity before invoking the handler.
1190
    // In some cases the temporary buffer needs to be flushed
1191
    // before it is full:
1192
    // * When the closing double quote is seen
1193
    // * When there in no more input (and more is expected later)
1194
    // A goal of the algorithm is to call the handler as few times
1195
    // as possible. Thus, when the first escape is encountered,
1196
    // the algorithm attempts to fill the temporary buffer first.
1197
    //
1198
47.1k
    auto const ev_too_large = is_key?
1199
41.7k
        error::key_too_large : error::string_too_large;
1200
47.1k
    auto const max_size = is_key?
1201
41.7k
        Handler::max_key_size : Handler::max_string_size;
1202
47.1k
    detail::clipped_const_stream cs(p, end_);
1203
47.1k
    detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1204
47.1k
    int digit;
1205
47.1k
    char c;
1206
47.1k
    cs.clip(temp.max_size());
1207
47.1k
    if(! stack_empty && ! st_.empty())
1208
605
    {
1209
605
        state st;
1210
605
        st_.pop(st);
1211
605
        st_.pop(total);
1212
605
        switch(st)
1213
605
        {
1214
0
        default: BOOST_JSON_UNREACHABLE();
1215
292
        case state::str2: goto do_str2;
1216
115
        case state::str3: goto do_str3;
1217
18
        case state::str4: goto do_str4;
1218
16
        case state::str5: goto do_str5;
1219
15
        case state::str6: goto do_str6;
1220
19
        case state::str7: goto do_str7;
1221
79
        case state::str8: goto do_str8;
1222
12
        case state::sur1: goto do_sur1;
1223
2
        case state::sur2: goto do_sur2;
1224
3
        case state::sur3: goto do_sur3;
1225
11
        case state::sur4: goto do_sur4;
1226
7
        case state::sur5: goto do_sur5;
1227
16
        case state::sur6: goto do_sur6;
1228
605
        }
1229
605
    }
1230
    // Unescaped JSON is never larger than its escaped version.
1231
    // To efficiently process only what will fit in the temporary buffer,
1232
    // the size of the input stream is temporarily "clipped" to the size
1233
    // of the temporary buffer.
1234
    // handle escaped character
1235
46.5k
    BOOST_ASSERT(*cs == '\\');
1236
46.5k
    ++cs;
1237
5.36M
do_str3:
1238
5.36M
    if(BOOST_JSON_UNLIKELY(! cs))
1239
1.63k
    {
1240
1.63k
        if(BOOST_JSON_LIKELY(! temp.empty()))
1241
1.42k
        {
1242
1.42k
            BOOST_ASSERT(total <= max_size);
1243
1.42k
            if(BOOST_JSON_UNLIKELY(
1244
1.42k
                temp.size() > max_size - total))
1245
0
            {
1246
0
                BOOST_STATIC_CONSTEXPR source_location loc
1247
0
                    = BOOST_CURRENT_LOCATION;
1248
0
                return fail(cs.begin(), ev_too_large, &loc);
1249
0
            }
1250
1.42k
            total += temp.size();
1251
1.42k
            {
1252
1.42k
                bool r = is_key
1253
1.42k
                    ? h_.on_key_part(temp.get(), total, ec_)
1254
1.42k
                    : h_.on_string_part(temp.get(), total, ec_);
1255
1256
1.42k
                if(BOOST_JSON_UNLIKELY(!r))
1257
0
                {
1258
0
                    return fail(cs.begin());
1259
0
                }
1260
1.42k
            }
1261
1.42k
            temp.clear();
1262
1.42k
        }
1263
1.63k
        cs.clip(temp.max_size());
1264
1.63k
        if(BOOST_JSON_UNLIKELY(! cs))
1265
338
            return maybe_suspend(cs.begin(), state::str3, total);
1266
1.63k
    }
1267
5.36M
    switch(*cs)
1268
5.36M
    {
1269
60
    default:
1270
60
        {
1271
60
            BOOST_STATIC_CONSTEXPR source_location loc
1272
60
                = BOOST_CURRENT_LOCATION;
1273
60
            return fail(cs.begin(), error::syntax, &loc);
1274
0
        }
1275
19.7k
    case '\x22': // '"'
1276
19.7k
        temp.push_back('\x22');
1277
19.7k
        ++cs;
1278
19.7k
        break;
1279
3.27M
    case '\\':
1280
3.27M
        temp.push_back('\\');
1281
3.27M
        ++cs;
1282
3.27M
        break;
1283
3.23k
    case '/':
1284
3.23k
        temp.push_back('/');
1285
3.23k
        ++cs;
1286
3.23k
        break;
1287
8.45k
    case 'b':
1288
8.45k
        temp.push_back('\x08');
1289
8.45k
        ++cs;
1290
8.45k
        break;
1291
48.0k
    case 'f':
1292
48.0k
        temp.push_back('\x0c');
1293
48.0k
        ++cs;
1294
48.0k
        break;
1295
17.1k
    case 'n':
1296
17.1k
        temp.push_back('\x0a');
1297
17.1k
        ++cs;
1298
17.1k
        break;
1299
2.11k
    case 'r':
1300
2.11k
        temp.push_back('\x0d');
1301
2.11k
        ++cs;
1302
2.11k
        break;
1303
1.28k
    case 't':
1304
1.28k
        temp.push_back('\x09');
1305
1.28k
        ++cs;
1306
1.28k
        break;
1307
1.99M
    case 'u':
1308
        // utf16 escape
1309
        //
1310
        // fast path only when the buffer
1311
        // is large enough for 2 surrogates
1312
1.99M
        if(BOOST_JSON_LIKELY(cs.remain() > 10))
1313
1.98M
        {
1314
            // KRYSTIAN TODO: this could be done
1315
            // with fewer instructions
1316
1.98M
            digit = detail::load_little_endian<4>(
1317
1.98M
                cs.begin() + 1);
1318
1.98M
            int d4 = detail::hex_digit(static_cast<
1319
1.98M
                unsigned char>(digit >> 24));
1320
1.98M
            int d3 = detail::hex_digit(static_cast<
1321
1.98M
                unsigned char>(digit >> 16));
1322
1.98M
            int d2 = detail::hex_digit(static_cast<
1323
1.98M
                unsigned char>(digit >> 8));
1324
1.98M
            int d1 = detail::hex_digit(static_cast<
1325
1.98M
                unsigned char>(digit));
1326
1.98M
            if(BOOST_JSON_UNLIKELY(
1327
1.98M
                (d1 | d2 | d3 | d4) == -1))
1328
127
            {
1329
127
                if(d1 != -1)
1330
78
                    ++cs;
1331
127
                if(d2 != -1)
1332
55
                    ++cs;
1333
127
                if(d3 != -1)
1334
44
                    ++cs;
1335
127
                BOOST_STATIC_CONSTEXPR source_location loc
1336
127
                    = BOOST_CURRENT_LOCATION;
1337
127
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1338
127
            }
1339
            // 32 bit unicode scalar value
1340
1.98M
            unsigned const u1 =
1341
1.98M
                (d1 << 12) + (d2 << 8) +
1342
1.98M
                (d3 << 4) + d4;
1343
            // valid unicode scalar values are
1344
            // [0, D7FF] and [E000, 10FFFF]
1345
            // values within this range are valid utf-8
1346
            // code points and invalid leading surrogates.
1347
1.98M
            if(BOOST_JSON_LIKELY(
1348
1.98M
                u1 < 0xd800 || u1 > 0xdfff))
1349
1.79M
            {
1350
1.79M
                cs += 5;
1351
1.79M
                temp.append_utf8(u1);
1352
1.79M
                break;
1353
1.79M
            }
1354
191k
            if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1355
19
            {
1356
19
                BOOST_STATIC_CONSTEXPR source_location loc
1357
19
                    = BOOST_CURRENT_LOCATION;
1358
19
                return fail(cs.begin(), error::illegal_leading_surrogate,
1359
19
                    &loc);
1360
19
            }
1361
191k
            cs += 5;
1362
            // KRYSTIAN TODO: this can be a two byte load
1363
            // and a single comparison. We lose error information,
1364
            // but it's faster.
1365
191k
            if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1366
24
            {
1367
24
                BOOST_STATIC_CONSTEXPR source_location loc
1368
24
                    = BOOST_CURRENT_LOCATION;
1369
24
                return fail(cs.begin(), error::syntax, &loc);
1370
24
            }
1371
191k
            ++cs;
1372
191k
            if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1373
23
            {
1374
23
                BOOST_STATIC_CONSTEXPR source_location loc
1375
23
                    = BOOST_CURRENT_LOCATION;
1376
23
                return fail(cs.begin(), error::syntax, &loc);
1377
23
            }
1378
191k
            ++cs;
1379
191k
            digit = detail::load_little_endian<4>(cs.begin());
1380
191k
            d4 = detail::hex_digit(static_cast<
1381
191k
                unsigned char>(digit >> 24));
1382
191k
            d3 = detail::hex_digit(static_cast<
1383
191k
                unsigned char>(digit >> 16));
1384
191k
            d2 = detail::hex_digit(static_cast<
1385
191k
                unsigned char>(digit >> 8));
1386
191k
            d1 = detail::hex_digit(static_cast<
1387
191k
                unsigned char>(digit));
1388
191k
            if(BOOST_JSON_UNLIKELY(
1389
191k
                (d1 | d2 | d3 | d4) == -1))
1390
109
            {
1391
109
                if(d1 != -1)
1392
45
                    ++cs;
1393
109
                if(d2 != -1)
1394
41
                    ++cs;
1395
109
                if(d3 != -1)
1396
41
                    ++cs;
1397
109
                BOOST_STATIC_CONSTEXPR source_location loc
1398
109
                    = BOOST_CURRENT_LOCATION;
1399
109
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1400
109
            }
1401
191k
            unsigned const u2 =
1402
191k
                (d1 << 12) + (d2 << 8) +
1403
191k
                (d3 << 4) + d4;
1404
            // valid trailing surrogates are [DC00, DFFF]
1405
191k
            if(BOOST_JSON_UNLIKELY(
1406
191k
                u2 < 0xdc00 || u2 > 0xdfff))
1407
43
            {
1408
43
                BOOST_STATIC_CONSTEXPR source_location loc
1409
43
                    = BOOST_CURRENT_LOCATION;
1410
43
                return fail(cs.begin(), error::illegal_trailing_surrogate,
1411
43
                    &loc);
1412
43
            }
1413
191k
            cs += 4;
1414
191k
            unsigned cp =
1415
191k
                ((u1 - 0xd800) << 10) +
1416
191k
                ((u2 - 0xdc00)) +
1417
191k
                    0x10000;
1418
            // utf-16 surrogate pair
1419
191k
            temp.append_utf8(cp);
1420
191k
            break;
1421
191k
        }
1422
        // flush
1423
5.68k
        if(BOOST_JSON_LIKELY(! temp.empty()))
1424
5.10k
        {
1425
5.10k
            BOOST_ASSERT(total <= max_size);
1426
5.10k
            if(BOOST_JSON_UNLIKELY(
1427
5.10k
                temp.size() > max_size - total))
1428
0
            {
1429
0
                BOOST_STATIC_CONSTEXPR source_location loc
1430
0
                    = BOOST_CURRENT_LOCATION;
1431
0
                return fail(cs.begin(), ev_too_large, &loc);
1432
0
            }
1433
5.10k
            total += temp.size();
1434
5.10k
            {
1435
5.10k
                bool r = is_key
1436
5.10k
                    ? h_.on_key_part(temp.get(), total, ec_)
1437
5.10k
                    : h_.on_string_part(temp.get(), total, ec_);
1438
1439
5.10k
                if(BOOST_JSON_UNLIKELY(!r))
1440
0
                {
1441
0
                    return fail(cs.begin());
1442
0
                }
1443
5.10k
            }
1444
5.10k
            temp.clear();
1445
5.10k
            cs.clip(temp.max_size());
1446
5.10k
        }
1447
5.68k
        ++cs;
1448
        // utf-16 escape
1449
5.70k
do_str4:
1450
5.70k
        if(BOOST_JSON_UNLIKELY(! cs))
1451
55
            return maybe_suspend(cs.begin(), state::str4, total);
1452
5.64k
        digit = detail::hex_digit(*cs);
1453
5.64k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1454
41
        {
1455
41
            BOOST_STATIC_CONSTEXPR source_location loc
1456
41
                = BOOST_CURRENT_LOCATION;
1457
41
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1458
41
        }
1459
5.60k
        ++cs;
1460
5.60k
        u1_ = digit << 12;
1461
5.62k
do_str5:
1462
5.62k
        if(BOOST_JSON_UNLIKELY(! cs))
1463
56
            return maybe_suspend(cs.begin(), state::str5, total);
1464
5.56k
        digit = detail::hex_digit(*cs);
1465
5.56k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1466
53
        {
1467
53
            BOOST_STATIC_CONSTEXPR source_location loc
1468
53
                = BOOST_CURRENT_LOCATION;
1469
53
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1470
53
        }
1471
5.51k
        ++cs;
1472
5.51k
        u1_ += digit << 8;
1473
5.52k
do_str6:
1474
5.52k
        if(BOOST_JSON_UNLIKELY(! cs))
1475
54
            return maybe_suspend(cs.begin(), state::str6, total);
1476
5.47k
        digit = detail::hex_digit(*cs);
1477
5.47k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1478
43
        {
1479
43
            BOOST_STATIC_CONSTEXPR source_location loc
1480
43
                = BOOST_CURRENT_LOCATION;
1481
43
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1482
43
        }
1483
5.43k
        ++cs;
1484
5.43k
        u1_ += digit << 4;
1485
5.44k
do_str7:
1486
5.44k
        if(BOOST_JSON_UNLIKELY(! cs))
1487
67
            return maybe_suspend(cs.begin(), state::str7, total);
1488
5.38k
        digit = detail::hex_digit(*cs);
1489
5.38k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1490
18
        {
1491
18
            BOOST_STATIC_CONSTEXPR source_location loc
1492
18
                = BOOST_CURRENT_LOCATION;
1493
18
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1494
18
        }
1495
5.36k
        ++cs;
1496
5.36k
        u1_ += digit;
1497
5.36k
        if(BOOST_JSON_LIKELY(
1498
5.36k
            u1_ < 0xd800 || u1_ > 0xdfff))
1499
3.47k
        {
1500
3.47k
            BOOST_ASSERT(temp.empty());
1501
            // utf-8 codepoint
1502
3.47k
            temp.append_utf8(u1_);
1503
3.47k
            break;
1504
3.47k
        }
1505
1.89k
        if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1506
22
        {
1507
22
            BOOST_STATIC_CONSTEXPR source_location loc
1508
22
                = BOOST_CURRENT_LOCATION;
1509
22
            return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1510
22
        }
1511
1.88k
do_sur1:
1512
1.88k
        if(BOOST_JSON_UNLIKELY(! cs))
1513
40
            return maybe_suspend(cs.begin(), state::sur1, total);
1514
1.84k
        if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1515
18
        {
1516
18
            BOOST_STATIC_CONSTEXPR source_location loc
1517
18
                = BOOST_CURRENT_LOCATION;
1518
18
            return fail(cs.begin(), error::syntax, &loc);
1519
18
        }
1520
1.82k
        ++cs;
1521
1.82k
do_sur2:
1522
1.82k
        if(BOOST_JSON_UNLIKELY(! cs))
1523
6
            return maybe_suspend(cs.begin(), state::sur2, total);
1524
1.82k
        if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1525
2
        {
1526
2
            BOOST_STATIC_CONSTEXPR source_location loc
1527
2
                = BOOST_CURRENT_LOCATION;
1528
2
            return fail(cs.begin(), error::syntax, &loc);
1529
2
        }
1530
1.81k
        ++cs;
1531
1.82k
do_sur3:
1532
1.82k
        if(BOOST_JSON_UNLIKELY(! cs))
1533
7
            return maybe_suspend(cs.begin(), state::sur3, total);
1534
1.81k
        digit = detail::hex_digit(*cs);
1535
1.81k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1536
27
        {
1537
27
            BOOST_STATIC_CONSTEXPR source_location loc
1538
27
                = BOOST_CURRENT_LOCATION;
1539
27
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1540
27
        }
1541
1.78k
        ++cs;
1542
1.78k
        u2_ = digit << 12;
1543
1.79k
do_sur4:
1544
1.79k
        if(BOOST_JSON_UNLIKELY(! cs))
1545
31
            return maybe_suspend(cs.begin(), state::sur4, total);
1546
1.76k
        digit = detail::hex_digit(*cs);
1547
1.76k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1548
24
        {
1549
24
            BOOST_STATIC_CONSTEXPR source_location loc
1550
24
                = BOOST_CURRENT_LOCATION;
1551
24
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1552
24
        }
1553
1.74k
        ++cs;
1554
1.74k
        u2_ += digit << 8;
1555
1.75k
do_sur5:
1556
1.75k
        if(BOOST_JSON_UNLIKELY(! cs))
1557
22
            return maybe_suspend(cs.begin(), state::sur5, total);
1558
1.72k
        digit = detail::hex_digit(*cs);
1559
1.72k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1560
23
        {
1561
23
            BOOST_STATIC_CONSTEXPR source_location loc
1562
23
                = BOOST_CURRENT_LOCATION;
1563
23
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1564
23
        }
1565
1.70k
        ++cs;
1566
1.70k
        u2_ += digit << 4;
1567
1.72k
do_sur6:
1568
1.72k
        if(BOOST_JSON_UNLIKELY(! cs))
1569
51
            return maybe_suspend(cs.begin(), state::sur6, total);
1570
1.67k
        digit = detail::hex_digit(*cs);
1571
1.67k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1572
17
        {
1573
17
            BOOST_STATIC_CONSTEXPR source_location loc
1574
17
                = BOOST_CURRENT_LOCATION;
1575
17
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1576
17
        }
1577
1.65k
        ++cs;
1578
1.65k
        u2_ += digit;
1579
1.65k
        if(BOOST_JSON_UNLIKELY(
1580
1.65k
            u2_ < 0xdc00 || u2_ > 0xdfff))
1581
50
        {
1582
50
            BOOST_STATIC_CONSTEXPR source_location loc
1583
50
                = BOOST_CURRENT_LOCATION;
1584
50
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1585
50
        }
1586
1.60k
        unsigned cp =
1587
1.60k
            ((u1_ - 0xd800) << 10) +
1588
1.60k
            ((u2_ - 0xdc00)) +
1589
1.60k
                0x10000;
1590
1.60k
        BOOST_ASSERT(temp.empty());
1591
        // utf-16 surrogate pair
1592
1.60k
        temp.append_utf8(cp);
1593
5.36M
    }
1594
5.36M
do_str2:
1595
    // KRYSTIAN TODO: we can append the characters
1596
    // all at once instead of one at a time
1597
5.36M
    for(;;)
1598
47.4M
    {
1599
47.4M
        if(BOOST_JSON_UNLIKELY(! cs || temp.capacity() == 0 ))
1600
8.82k
        {
1601
            // flush
1602
8.82k
            if(BOOST_JSON_LIKELY(! temp.empty()))
1603
8.53k
            {
1604
8.53k
                BOOST_ASSERT(total <= max_size);
1605
8.53k
                if(BOOST_JSON_UNLIKELY(
1606
8.53k
                    temp.size() > max_size - total))
1607
0
                {
1608
0
                    BOOST_STATIC_CONSTEXPR source_location loc
1609
0
                        = BOOST_CURRENT_LOCATION;
1610
0
                    return fail(cs.begin(), ev_too_large, &loc);
1611
0
                }
1612
8.53k
                total += temp.size();
1613
8.53k
                {
1614
8.53k
                    bool r = is_key
1615
8.53k
                        ? h_.on_key_part(temp.get(), total, ec_)
1616
8.53k
                        : h_.on_string_part(temp.get(), total, ec_);
1617
1618
8.53k
                    if(BOOST_JSON_UNLIKELY(!r))
1619
0
                    {
1620
0
                        return fail(cs.begin());
1621
0
                    }
1622
8.53k
                }
1623
8.53k
                temp.clear();
1624
8.53k
            }
1625
8.82k
            cs.clip(temp.max_size());
1626
8.82k
            if(BOOST_JSON_UNLIKELY(! cs))
1627
915
                return maybe_suspend(cs.begin(), state::str2, total);
1628
8.82k
        }
1629
47.4M
        c = *cs;
1630
47.4M
        if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
1631
44.1k
        {
1632
44.1k
            BOOST_ASSERT(total <= max_size);
1633
44.1k
            if(BOOST_JSON_UNLIKELY(
1634
44.1k
                temp.size() > max_size - total))
1635
0
            {
1636
0
                BOOST_STATIC_CONSTEXPR source_location loc
1637
0
                    = BOOST_CURRENT_LOCATION;
1638
0
                return fail(cs.begin(), ev_too_large, &loc);
1639
0
            }
1640
44.1k
            total += temp.size();
1641
44.1k
            {
1642
44.1k
                bool r = is_key
1643
44.1k
                    ? h_.on_key(temp.get(), total, ec_)
1644
44.1k
                    : h_.on_string(temp.get(), total, ec_);
1645
1646
44.1k
                if(BOOST_JSON_UNLIKELY(!r))
1647
0
                {
1648
0
                    return fail(cs.begin());
1649
0
                }
1650
44.1k
            }
1651
44.1k
            ++cs;
1652
44.1k
            return cs.begin();
1653
44.1k
        }
1654
47.3M
        else if((c & 0x80) && !allow_bad_utf8)
1655
390k
        {
1656
390k
            seq_.save(cs.begin(), cs.remain());
1657
390k
            if(BOOST_JSON_UNLIKELY(! seq_.complete()))
1658
990
            {
1659
990
                if(BOOST_JSON_LIKELY(! temp.empty()))
1660
982
                {
1661
982
                    BOOST_ASSERT(total <= max_size);
1662
982
                    if(BOOST_JSON_UNLIKELY(
1663
982
                        temp.size() > max_size - total))
1664
0
                    {
1665
0
                        BOOST_STATIC_CONSTEXPR source_location loc
1666
0
                            = BOOST_CURRENT_LOCATION;
1667
0
                        return fail(cs.begin(), ev_too_large, &loc);
1668
0
                    }
1669
982
                    total += temp.size();
1670
982
                    {
1671
982
                        bool r = is_key
1672
982
                            ? h_.on_key_part(temp.get(), total, ec_)
1673
982
                            : h_.on_string_part(temp.get(), total, ec_);
1674
1675
982
                        if(BOOST_JSON_UNLIKELY(!r))
1676
0
                        {
1677
0
                            return fail(cs.begin());
1678
0
                        }
1679
982
                    }
1680
982
                    temp.clear();
1681
982
                }
1682
990
                cs = cs.end();
1683
                // ensure there is room for the saved byte sequence
1684
990
                cs.clip(temp.max_size() - seq_.length());
1685
990
                goto do_str8;
1686
990
            }
1687
389k
            if(BOOST_JSON_UNLIKELY(! seq_.valid()))
1688
305
            {
1689
305
                BOOST_STATIC_CONSTEXPR source_location loc
1690
305
                    = BOOST_CURRENT_LOCATION;
1691
305
                return fail(cs.begin(), error::syntax, &loc);
1692
305
            }
1693
389k
            temp.append(seq_.data(), seq_.length());
1694
389k
            cs += seq_.length();
1695
389k
            continue;
1696
389k
        }
1697
46.9M
        else if(BOOST_JSON_LIKELY(c == '\\'))
1698
5.31M
        {
1699
5.31M
            ++cs;
1700
5.31M
            goto do_str3;
1701
5.31M
        }
1702
41.6M
        else if(BOOST_JSON_UNLIKELY(
1703
41.6M
            detail::is_control(c)))
1704
91
        {
1705
91
            BOOST_STATIC_CONSTEXPR source_location loc
1706
91
                = BOOST_CURRENT_LOCATION;
1707
91
            return fail(cs.begin(), error::syntax, &loc);
1708
91
        }
1709
41.6M
        temp.push_back(c);
1710
41.6M
        ++cs;
1711
41.6M
    }
1712
1.06k
do_str8:
1713
1.06k
    uint8_t needed = seq_.needed();
1714
1.06k
    if(BOOST_JSON_UNLIKELY(
1715
1.06k
        ! seq_.append(cs.begin(), cs.remain())))
1716
159
        return maybe_suspend(cs.end(), state::str8, total);
1717
910
    if(BOOST_JSON_UNLIKELY(! seq_.valid()))
1718
11
    {
1719
11
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1720
11
        return fail(cs.begin(), error::syntax, &loc);
1721
11
    }
1722
899
    temp.append(seq_.data(), seq_.length());
1723
899
    cs += needed;
1724
899
    goto do_str2;
1725
910
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_escaped<true>(char const*, unsigned long, std::__1::integral_constant<bool, true>, bool, bool)
Line
Count
Source
1184
46.5k
{
1185
    //---------------------------------------------------------------
1186
    //
1187
    // To handle escapes, a local temporary buffer accumulates
1188
    // the unescaped result. The algorithm attempts to fill the
1189
    // buffer to capacity before invoking the handler.
1190
    // In some cases the temporary buffer needs to be flushed
1191
    // before it is full:
1192
    // * When the closing double quote is seen
1193
    // * When there in no more input (and more is expected later)
1194
    // A goal of the algorithm is to call the handler as few times
1195
    // as possible. Thus, when the first escape is encountered,
1196
    // the algorithm attempts to fill the temporary buffer first.
1197
    //
1198
46.5k
    auto const ev_too_large = is_key?
1199
41.2k
        error::key_too_large : error::string_too_large;
1200
46.5k
    auto const max_size = is_key?
1201
41.2k
        Handler::max_key_size : Handler::max_string_size;
1202
46.5k
    detail::clipped_const_stream cs(p, end_);
1203
46.5k
    detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1204
46.5k
    int digit;
1205
46.5k
    char c;
1206
46.5k
    cs.clip(temp.max_size());
1207
46.5k
    if(! stack_empty && ! st_.empty())
1208
0
    {
1209
0
        state st;
1210
0
        st_.pop(st);
1211
0
        st_.pop(total);
1212
0
        switch(st)
1213
0
        {
1214
0
        default: BOOST_JSON_UNREACHABLE();
1215
0
        case state::str2: goto do_str2;
1216
0
        case state::str3: goto do_str3;
1217
0
        case state::str4: goto do_str4;
1218
0
        case state::str5: goto do_str5;
1219
0
        case state::str6: goto do_str6;
1220
0
        case state::str7: goto do_str7;
1221
0
        case state::str8: goto do_str8;
1222
0
        case state::sur1: goto do_sur1;
1223
0
        case state::sur2: goto do_sur2;
1224
0
        case state::sur3: goto do_sur3;
1225
0
        case state::sur4: goto do_sur4;
1226
0
        case state::sur5: goto do_sur5;
1227
0
        case state::sur6: goto do_sur6;
1228
0
        }
1229
0
    }
1230
    // Unescaped JSON is never larger than its escaped version.
1231
    // To efficiently process only what will fit in the temporary buffer,
1232
    // the size of the input stream is temporarily "clipped" to the size
1233
    // of the temporary buffer.
1234
    // handle escaped character
1235
46.5k
    BOOST_ASSERT(*cs == '\\');
1236
46.5k
    ++cs;
1237
5.36M
do_str3:
1238
5.36M
    if(BOOST_JSON_UNLIKELY(! cs))
1239
1.51k
    {
1240
1.51k
        if(BOOST_JSON_LIKELY(! temp.empty()))
1241
1.42k
        {
1242
1.42k
            BOOST_ASSERT(total <= max_size);
1243
1.42k
            if(BOOST_JSON_UNLIKELY(
1244
1.42k
                temp.size() > max_size - total))
1245
0
            {
1246
0
                BOOST_STATIC_CONSTEXPR source_location loc
1247
0
                    = BOOST_CURRENT_LOCATION;
1248
0
                return fail(cs.begin(), ev_too_large, &loc);
1249
0
            }
1250
1.42k
            total += temp.size();
1251
1.42k
            {
1252
1.42k
                bool r = is_key
1253
1.42k
                    ? h_.on_key_part(temp.get(), total, ec_)
1254
1.42k
                    : h_.on_string_part(temp.get(), total, ec_);
1255
1256
1.42k
                if(BOOST_JSON_UNLIKELY(!r))
1257
0
                {
1258
0
                    return fail(cs.begin());
1259
0
                }
1260
1.42k
            }
1261
1.42k
            temp.clear();
1262
1.42k
        }
1263
1.51k
        cs.clip(temp.max_size());
1264
1.51k
        if(BOOST_JSON_UNLIKELY(! cs))
1265
223
            return maybe_suspend(cs.begin(), state::str3, total);
1266
1.51k
    }
1267
5.36M
    switch(*cs)
1268
5.36M
    {
1269
60
    default:
1270
60
        {
1271
60
            BOOST_STATIC_CONSTEXPR source_location loc
1272
60
                = BOOST_CURRENT_LOCATION;
1273
60
            return fail(cs.begin(), error::syntax, &loc);
1274
0
        }
1275
19.7k
    case '\x22': // '"'
1276
19.7k
        temp.push_back('\x22');
1277
19.7k
        ++cs;
1278
19.7k
        break;
1279
3.27M
    case '\\':
1280
3.27M
        temp.push_back('\\');
1281
3.27M
        ++cs;
1282
3.27M
        break;
1283
3.23k
    case '/':
1284
3.23k
        temp.push_back('/');
1285
3.23k
        ++cs;
1286
3.23k
        break;
1287
8.45k
    case 'b':
1288
8.45k
        temp.push_back('\x08');
1289
8.45k
        ++cs;
1290
8.45k
        break;
1291
48.0k
    case 'f':
1292
48.0k
        temp.push_back('\x0c');
1293
48.0k
        ++cs;
1294
48.0k
        break;
1295
17.1k
    case 'n':
1296
17.1k
        temp.push_back('\x0a');
1297
17.1k
        ++cs;
1298
17.1k
        break;
1299
2.11k
    case 'r':
1300
2.11k
        temp.push_back('\x0d');
1301
2.11k
        ++cs;
1302
2.11k
        break;
1303
1.28k
    case 't':
1304
1.28k
        temp.push_back('\x09');
1305
1.28k
        ++cs;
1306
1.28k
        break;
1307
1.99M
    case 'u':
1308
        // utf16 escape
1309
        //
1310
        // fast path only when the buffer
1311
        // is large enough for 2 surrogates
1312
1.99M
        if(BOOST_JSON_LIKELY(cs.remain() > 10))
1313
1.98M
        {
1314
            // KRYSTIAN TODO: this could be done
1315
            // with fewer instructions
1316
1.98M
            digit = detail::load_little_endian<4>(
1317
1.98M
                cs.begin() + 1);
1318
1.98M
            int d4 = detail::hex_digit(static_cast<
1319
1.98M
                unsigned char>(digit >> 24));
1320
1.98M
            int d3 = detail::hex_digit(static_cast<
1321
1.98M
                unsigned char>(digit >> 16));
1322
1.98M
            int d2 = detail::hex_digit(static_cast<
1323
1.98M
                unsigned char>(digit >> 8));
1324
1.98M
            int d1 = detail::hex_digit(static_cast<
1325
1.98M
                unsigned char>(digit));
1326
1.98M
            if(BOOST_JSON_UNLIKELY(
1327
1.98M
                (d1 | d2 | d3 | d4) == -1))
1328
127
            {
1329
127
                if(d1 != -1)
1330
78
                    ++cs;
1331
127
                if(d2 != -1)
1332
55
                    ++cs;
1333
127
                if(d3 != -1)
1334
44
                    ++cs;
1335
127
                BOOST_STATIC_CONSTEXPR source_location loc
1336
127
                    = BOOST_CURRENT_LOCATION;
1337
127
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1338
127
            }
1339
            // 32 bit unicode scalar value
1340
1.98M
            unsigned const u1 =
1341
1.98M
                (d1 << 12) + (d2 << 8) +
1342
1.98M
                (d3 << 4) + d4;
1343
            // valid unicode scalar values are
1344
            // [0, D7FF] and [E000, 10FFFF]
1345
            // values within this range are valid utf-8
1346
            // code points and invalid leading surrogates.
1347
1.98M
            if(BOOST_JSON_LIKELY(
1348
1.98M
                u1 < 0xd800 || u1 > 0xdfff))
1349
1.79M
            {
1350
1.79M
                cs += 5;
1351
1.79M
                temp.append_utf8(u1);
1352
1.79M
                break;
1353
1.79M
            }
1354
191k
            if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1355
19
            {
1356
19
                BOOST_STATIC_CONSTEXPR source_location loc
1357
19
                    = BOOST_CURRENT_LOCATION;
1358
19
                return fail(cs.begin(), error::illegal_leading_surrogate,
1359
19
                    &loc);
1360
19
            }
1361
191k
            cs += 5;
1362
            // KRYSTIAN TODO: this can be a two byte load
1363
            // and a single comparison. We lose error information,
1364
            // but it's faster.
1365
191k
            if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1366
24
            {
1367
24
                BOOST_STATIC_CONSTEXPR source_location loc
1368
24
                    = BOOST_CURRENT_LOCATION;
1369
24
                return fail(cs.begin(), error::syntax, &loc);
1370
24
            }
1371
191k
            ++cs;
1372
191k
            if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1373
23
            {
1374
23
                BOOST_STATIC_CONSTEXPR source_location loc
1375
23
                    = BOOST_CURRENT_LOCATION;
1376
23
                return fail(cs.begin(), error::syntax, &loc);
1377
23
            }
1378
191k
            ++cs;
1379
191k
            digit = detail::load_little_endian<4>(cs.begin());
1380
191k
            d4 = detail::hex_digit(static_cast<
1381
191k
                unsigned char>(digit >> 24));
1382
191k
            d3 = detail::hex_digit(static_cast<
1383
191k
                unsigned char>(digit >> 16));
1384
191k
            d2 = detail::hex_digit(static_cast<
1385
191k
                unsigned char>(digit >> 8));
1386
191k
            d1 = detail::hex_digit(static_cast<
1387
191k
                unsigned char>(digit));
1388
191k
            if(BOOST_JSON_UNLIKELY(
1389
191k
                (d1 | d2 | d3 | d4) == -1))
1390
109
            {
1391
109
                if(d1 != -1)
1392
45
                    ++cs;
1393
109
                if(d2 != -1)
1394
41
                    ++cs;
1395
109
                if(d3 != -1)
1396
41
                    ++cs;
1397
109
                BOOST_STATIC_CONSTEXPR source_location loc
1398
109
                    = BOOST_CURRENT_LOCATION;
1399
109
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1400
109
            }
1401
191k
            unsigned const u2 =
1402
191k
                (d1 << 12) + (d2 << 8) +
1403
191k
                (d3 << 4) + d4;
1404
            // valid trailing surrogates are [DC00, DFFF]
1405
191k
            if(BOOST_JSON_UNLIKELY(
1406
191k
                u2 < 0xdc00 || u2 > 0xdfff))
1407
43
            {
1408
43
                BOOST_STATIC_CONSTEXPR source_location loc
1409
43
                    = BOOST_CURRENT_LOCATION;
1410
43
                return fail(cs.begin(), error::illegal_trailing_surrogate,
1411
43
                    &loc);
1412
43
            }
1413
191k
            cs += 4;
1414
191k
            unsigned cp =
1415
191k
                ((u1 - 0xd800) << 10) +
1416
191k
                ((u2 - 0xdc00)) +
1417
191k
                    0x10000;
1418
            // utf-16 surrogate pair
1419
191k
            temp.append_utf8(cp);
1420
191k
            break;
1421
191k
        }
1422
        // flush
1423
5.68k
        if(BOOST_JSON_LIKELY(! temp.empty()))
1424
5.10k
        {
1425
5.10k
            BOOST_ASSERT(total <= max_size);
1426
5.10k
            if(BOOST_JSON_UNLIKELY(
1427
5.10k
                temp.size() > max_size - total))
1428
0
            {
1429
0
                BOOST_STATIC_CONSTEXPR source_location loc
1430
0
                    = BOOST_CURRENT_LOCATION;
1431
0
                return fail(cs.begin(), ev_too_large, &loc);
1432
0
            }
1433
5.10k
            total += temp.size();
1434
5.10k
            {
1435
5.10k
                bool r = is_key
1436
5.10k
                    ? h_.on_key_part(temp.get(), total, ec_)
1437
5.10k
                    : h_.on_string_part(temp.get(), total, ec_);
1438
1439
5.10k
                if(BOOST_JSON_UNLIKELY(!r))
1440
0
                {
1441
0
                    return fail(cs.begin());
1442
0
                }
1443
5.10k
            }
1444
5.10k
            temp.clear();
1445
5.10k
            cs.clip(temp.max_size());
1446
5.10k
        }
1447
5.68k
        ++cs;
1448
        // utf-16 escape
1449
5.68k
do_str4:
1450
5.68k
        if(BOOST_JSON_UNLIKELY(! cs))
1451
37
            return maybe_suspend(cs.begin(), state::str4, total);
1452
5.64k
        digit = detail::hex_digit(*cs);
1453
5.64k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1454
41
        {
1455
41
            BOOST_STATIC_CONSTEXPR source_location loc
1456
41
                = BOOST_CURRENT_LOCATION;
1457
41
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1458
41
        }
1459
5.60k
        ++cs;
1460
5.60k
        u1_ = digit << 12;
1461
5.60k
do_str5:
1462
5.60k
        if(BOOST_JSON_UNLIKELY(! cs))
1463
40
            return maybe_suspend(cs.begin(), state::str5, total);
1464
5.56k
        digit = detail::hex_digit(*cs);
1465
5.56k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1466
53
        {
1467
53
            BOOST_STATIC_CONSTEXPR source_location loc
1468
53
                = BOOST_CURRENT_LOCATION;
1469
53
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1470
53
        }
1471
5.51k
        ++cs;
1472
5.51k
        u1_ += digit << 8;
1473
5.51k
do_str6:
1474
5.51k
        if(BOOST_JSON_UNLIKELY(! cs))
1475
39
            return maybe_suspend(cs.begin(), state::str6, total);
1476
5.47k
        digit = detail::hex_digit(*cs);
1477
5.47k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1478
43
        {
1479
43
            BOOST_STATIC_CONSTEXPR source_location loc
1480
43
                = BOOST_CURRENT_LOCATION;
1481
43
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1482
43
        }
1483
5.43k
        ++cs;
1484
5.43k
        u1_ += digit << 4;
1485
5.43k
do_str7:
1486
5.43k
        if(BOOST_JSON_UNLIKELY(! cs))
1487
48
            return maybe_suspend(cs.begin(), state::str7, total);
1488
5.38k
        digit = detail::hex_digit(*cs);
1489
5.38k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1490
18
        {
1491
18
            BOOST_STATIC_CONSTEXPR source_location loc
1492
18
                = BOOST_CURRENT_LOCATION;
1493
18
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1494
18
        }
1495
5.36k
        ++cs;
1496
5.36k
        u1_ += digit;
1497
5.36k
        if(BOOST_JSON_LIKELY(
1498
5.36k
            u1_ < 0xd800 || u1_ > 0xdfff))
1499
3.47k
        {
1500
3.47k
            BOOST_ASSERT(temp.empty());
1501
            // utf-8 codepoint
1502
3.47k
            temp.append_utf8(u1_);
1503
3.47k
            break;
1504
3.47k
        }
1505
1.89k
        if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1506
22
        {
1507
22
            BOOST_STATIC_CONSTEXPR source_location loc
1508
22
                = BOOST_CURRENT_LOCATION;
1509
22
            return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1510
22
        }
1511
1.87k
do_sur1:
1512
1.87k
        if(BOOST_JSON_UNLIKELY(! cs))
1513
28
            return maybe_suspend(cs.begin(), state::sur1, total);
1514
1.84k
        if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1515
18
        {
1516
18
            BOOST_STATIC_CONSTEXPR source_location loc
1517
18
                = BOOST_CURRENT_LOCATION;
1518
18
            return fail(cs.begin(), error::syntax, &loc);
1519
18
        }
1520
1.82k
        ++cs;
1521
1.82k
do_sur2:
1522
1.82k
        if(BOOST_JSON_UNLIKELY(! cs))
1523
4
            return maybe_suspend(cs.begin(), state::sur2, total);
1524
1.82k
        if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1525
2
        {
1526
2
            BOOST_STATIC_CONSTEXPR source_location loc
1527
2
                = BOOST_CURRENT_LOCATION;
1528
2
            return fail(cs.begin(), error::syntax, &loc);
1529
2
        }
1530
1.81k
        ++cs;
1531
1.81k
do_sur3:
1532
1.81k
        if(BOOST_JSON_UNLIKELY(! cs))
1533
4
            return maybe_suspend(cs.begin(), state::sur3, total);
1534
1.81k
        digit = detail::hex_digit(*cs);
1535
1.81k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1536
27
        {
1537
27
            BOOST_STATIC_CONSTEXPR source_location loc
1538
27
                = BOOST_CURRENT_LOCATION;
1539
27
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1540
27
        }
1541
1.78k
        ++cs;
1542
1.78k
        u2_ = digit << 12;
1543
1.78k
do_sur4:
1544
1.78k
        if(BOOST_JSON_UNLIKELY(! cs))
1545
20
            return maybe_suspend(cs.begin(), state::sur4, total);
1546
1.76k
        digit = detail::hex_digit(*cs);
1547
1.76k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1548
24
        {
1549
24
            BOOST_STATIC_CONSTEXPR source_location loc
1550
24
                = BOOST_CURRENT_LOCATION;
1551
24
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1552
24
        }
1553
1.74k
        ++cs;
1554
1.74k
        u2_ += digit << 8;
1555
1.74k
do_sur5:
1556
1.74k
        if(BOOST_JSON_UNLIKELY(! cs))
1557
15
            return maybe_suspend(cs.begin(), state::sur5, total);
1558
1.72k
        digit = detail::hex_digit(*cs);
1559
1.72k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1560
23
        {
1561
23
            BOOST_STATIC_CONSTEXPR source_location loc
1562
23
                = BOOST_CURRENT_LOCATION;
1563
23
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1564
23
        }
1565
1.70k
        ++cs;
1566
1.70k
        u2_ += digit << 4;
1567
1.70k
do_sur6:
1568
1.70k
        if(BOOST_JSON_UNLIKELY(! cs))
1569
35
            return maybe_suspend(cs.begin(), state::sur6, total);
1570
1.67k
        digit = detail::hex_digit(*cs);
1571
1.67k
        if(BOOST_JSON_UNLIKELY(digit == -1))
1572
17
        {
1573
17
            BOOST_STATIC_CONSTEXPR source_location loc
1574
17
                = BOOST_CURRENT_LOCATION;
1575
17
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1576
17
        }
1577
1.65k
        ++cs;
1578
1.65k
        u2_ += digit;
1579
1.65k
        if(BOOST_JSON_UNLIKELY(
1580
1.65k
            u2_ < 0xdc00 || u2_ > 0xdfff))
1581
50
        {
1582
50
            BOOST_STATIC_CONSTEXPR source_location loc
1583
50
                = BOOST_CURRENT_LOCATION;
1584
50
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1585
50
        }
1586
1.60k
        unsigned cp =
1587
1.60k
            ((u1_ - 0xd800) << 10) +
1588
1.60k
            ((u2_ - 0xdc00)) +
1589
1.60k
                0x10000;
1590
1.60k
        BOOST_ASSERT(temp.empty());
1591
        // utf-16 surrogate pair
1592
1.60k
        temp.append_utf8(cp);
1593
5.36M
    }
1594
5.36M
do_str2:
1595
    // KRYSTIAN TODO: we can append the characters
1596
    // all at once instead of one at a time
1597
5.36M
    for(;;)
1598
47.4M
    {
1599
47.4M
        if(BOOST_JSON_UNLIKELY(! cs || temp.capacity() == 0 ))
1600
8.53k
        {
1601
            // flush
1602
8.53k
            if(BOOST_JSON_LIKELY(! temp.empty()))
1603
8.53k
            {
1604
8.53k
                BOOST_ASSERT(total <= max_size);
1605
8.53k
                if(BOOST_JSON_UNLIKELY(
1606
8.53k
                    temp.size() > max_size - total))
1607
0
                {
1608
0
                    BOOST_STATIC_CONSTEXPR source_location loc
1609
0
                        = BOOST_CURRENT_LOCATION;
1610
0
                    return fail(cs.begin(), ev_too_large, &loc);
1611
0
                }
1612
8.53k
                total += temp.size();
1613
8.53k
                {
1614
8.53k
                    bool r = is_key
1615
8.53k
                        ? h_.on_key_part(temp.get(), total, ec_)
1616
8.53k
                        : h_.on_string_part(temp.get(), total, ec_);
1617
1618
8.53k
                    if(BOOST_JSON_UNLIKELY(!r))
1619
0
                    {
1620
0
                        return fail(cs.begin());
1621
0
                    }
1622
8.53k
                }
1623
8.53k
                temp.clear();
1624
8.53k
            }
1625
8.53k
            cs.clip(temp.max_size());
1626
8.53k
            if(BOOST_JSON_UNLIKELY(! cs))
1627
623
                return maybe_suspend(cs.begin(), state::str2, total);
1628
8.53k
        }
1629
47.4M
        c = *cs;
1630
47.4M
        if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
1631
44.1k
        {
1632
44.1k
            BOOST_ASSERT(total <= max_size);
1633
44.1k
            if(BOOST_JSON_UNLIKELY(
1634
44.1k
                temp.size() > max_size - total))
1635
0
            {
1636
0
                BOOST_STATIC_CONSTEXPR source_location loc
1637
0
                    = BOOST_CURRENT_LOCATION;
1638
0
                return fail(cs.begin(), ev_too_large, &loc);
1639
0
            }
1640
44.1k
            total += temp.size();
1641
44.1k
            {
1642
44.1k
                bool r = is_key
1643
44.1k
                    ? h_.on_key(temp.get(), total, ec_)
1644
44.1k
                    : h_.on_string(temp.get(), total, ec_);
1645
1646
44.1k
                if(BOOST_JSON_UNLIKELY(!r))
1647
0
                {
1648
0
                    return fail(cs.begin());
1649
0
                }
1650
44.1k
            }
1651
44.1k
            ++cs;
1652
44.1k
            return cs.begin();
1653
44.1k
        }
1654
47.3M
        else if((c & 0x80) && !allow_bad_utf8)
1655
390k
        {
1656
390k
            seq_.save(cs.begin(), cs.remain());
1657
390k
            if(BOOST_JSON_UNLIKELY(! seq_.complete()))
1658
990
            {
1659
990
                if(BOOST_JSON_LIKELY(! temp.empty()))
1660
982
                {
1661
982
                    BOOST_ASSERT(total <= max_size);
1662
982
                    if(BOOST_JSON_UNLIKELY(
1663
982
                        temp.size() > max_size - total))
1664
0
                    {
1665
0
                        BOOST_STATIC_CONSTEXPR source_location loc
1666
0
                            = BOOST_CURRENT_LOCATION;
1667
0
                        return fail(cs.begin(), ev_too_large, &loc);
1668
0
                    }
1669
982
                    total += temp.size();
1670
982
                    {
1671
982
                        bool r = is_key
1672
982
                            ? h_.on_key_part(temp.get(), total, ec_)
1673
982
                            : h_.on_string_part(temp.get(), total, ec_);
1674
1675
982
                        if(BOOST_JSON_UNLIKELY(!r))
1676
0
                        {
1677
0
                            return fail(cs.begin());
1678
0
                        }
1679
982
                    }
1680
982
                    temp.clear();
1681
982
                }
1682
990
                cs = cs.end();
1683
                // ensure there is room for the saved byte sequence
1684
990
                cs.clip(temp.max_size() - seq_.length());
1685
990
                goto do_str8;
1686
990
            }
1687
389k
            if(BOOST_JSON_UNLIKELY(! seq_.valid()))
1688
305
            {
1689
305
                BOOST_STATIC_CONSTEXPR source_location loc
1690
305
                    = BOOST_CURRENT_LOCATION;
1691
305
                return fail(cs.begin(), error::syntax, &loc);
1692
305
            }
1693
389k
            temp.append(seq_.data(), seq_.length());
1694
389k
            cs += seq_.length();
1695
389k
            continue;
1696
389k
        }
1697
46.9M
        else if(BOOST_JSON_LIKELY(c == '\\'))
1698
5.31M
        {
1699
5.31M
            ++cs;
1700
5.31M
            goto do_str3;
1701
5.31M
        }
1702
41.6M
        else if(BOOST_JSON_UNLIKELY(
1703
41.6M
            detail::is_control(c)))
1704
91
        {
1705
91
            BOOST_STATIC_CONSTEXPR source_location loc
1706
91
                = BOOST_CURRENT_LOCATION;
1707
91
            return fail(cs.begin(), error::syntax, &loc);
1708
91
        }
1709
41.6M
        temp.push_back(c);
1710
41.6M
        ++cs;
1711
41.6M
    }
1712
990
do_str8:
1713
990
    uint8_t needed = seq_.needed();
1714
990
    if(BOOST_JSON_UNLIKELY(
1715
990
        ! seq_.append(cs.begin(), cs.remain())))
1716
80
        return maybe_suspend(cs.end(), state::str8, total);
1717
910
    if(BOOST_JSON_UNLIKELY(! seq_.valid()))
1718
11
    {
1719
11
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1720
11
        return fail(cs.begin(), error::syntax, &loc);
1721
11
    }
1722
899
    temp.append(seq_.data(), seq_.length());
1723
899
    cs += needed;
1724
899
    goto do_str2;
1725
910
}
char const* boost::json::basic_parser<boost::json::detail::handler>::parse_escaped<false>(char const*, unsigned long, std::__1::integral_constant<bool, false>, bool, bool)
Line
Count
Source
1184
605
{
1185
    //---------------------------------------------------------------
1186
    //
1187
    // To handle escapes, a local temporary buffer accumulates
1188
    // the unescaped result. The algorithm attempts to fill the
1189
    // buffer to capacity before invoking the handler.
1190
    // In some cases the temporary buffer needs to be flushed
1191
    // before it is full:
1192
    // * When the closing double quote is seen
1193
    // * When there in no more input (and more is expected later)
1194
    // A goal of the algorithm is to call the handler as few times
1195
    // as possible. Thus, when the first escape is encountered,
1196
    // the algorithm attempts to fill the temporary buffer first.
1197
    //
1198
605
    auto const ev_too_large = is_key?
1199
521
        error::key_too_large : error::string_too_large;
1200
605
    auto const max_size = is_key?
1201
521
        Handler::max_key_size : Handler::max_string_size;
1202
605
    detail::clipped_const_stream cs(p, end_);
1203
605
    detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1204
605
    int digit;
1205
605
    char c;
1206
605
    cs.clip(temp.max_size());
1207
605
    if(! stack_empty && ! st_.empty())
1208
605
    {
1209
605
        state st;
1210
605
        st_.pop(st);
1211
605
        st_.pop(total);
1212
605
        switch(st)
1213
605
        {
1214
0
        default: BOOST_JSON_UNREACHABLE();
1215
292
        case state::str2: goto do_str2;
1216
115
        case state::str3: goto do_str3;
1217
18
        case state::str4: goto do_str4;
1218
16
        case state::str5: goto do_str5;
1219
15
        case state::str6: goto do_str6;
1220
19
        case state::str7: goto do_str7;
1221
79
        case state::str8: goto do_str8;
1222
12
        case state::sur1: goto do_sur1;
1223
2
        case state::sur2: goto do_sur2;
1224
3
        case state::sur3: goto do_sur3;
1225
11
        case state::sur4: goto do_sur4;
1226
7
        case state::sur5: goto do_sur5;
1227
16
        case state::sur6: goto do_sur6;
1228
605
        }
1229
605
    }
1230
    // Unescaped JSON is never larger than its escaped version.
1231
    // To efficiently process only what will fit in the temporary buffer,
1232
    // the size of the input stream is temporarily "clipped" to the size
1233
    // of the temporary buffer.
1234
    // handle escaped character
1235
0
    BOOST_ASSERT(*cs == '\\');
1236
0
    ++cs;
1237
115
do_str3:
1238
115
    if(BOOST_JSON_UNLIKELY(! cs))
1239
115
    {
1240
115
        if(BOOST_JSON_LIKELY(! temp.empty()))
1241
0
        {
1242
0
            BOOST_ASSERT(total <= max_size);
1243
0
            if(BOOST_JSON_UNLIKELY(
1244
0
                temp.size() > max_size - total))
1245
0
            {
1246
0
                BOOST_STATIC_CONSTEXPR source_location loc
1247
0
                    = BOOST_CURRENT_LOCATION;
1248
0
                return fail(cs.begin(), ev_too_large, &loc);
1249
0
            }
1250
0
            total += temp.size();
1251
0
            {
1252
0
                bool r = is_key
1253
0
                    ? h_.on_key_part(temp.get(), total, ec_)
1254
0
                    : h_.on_string_part(temp.get(), total, ec_);
1255
1256
0
                if(BOOST_JSON_UNLIKELY(!r))
1257
0
                {
1258
0
                    return fail(cs.begin());
1259
0
                }
1260
0
            }
1261
0
            temp.clear();
1262
0
        }
1263
115
        cs.clip(temp.max_size());
1264
115
        if(BOOST_JSON_UNLIKELY(! cs))
1265
115
            return maybe_suspend(cs.begin(), state::str3, total);
1266
115
    }
1267
0
    switch(*cs)
1268
0
    {
1269
0
    default:
1270
0
        {
1271
0
            BOOST_STATIC_CONSTEXPR source_location loc
1272
0
                = BOOST_CURRENT_LOCATION;
1273
0
            return fail(cs.begin(), error::syntax, &loc);
1274
0
        }
1275
0
    case '\x22': // '"'
1276
0
        temp.push_back('\x22');
1277
0
        ++cs;
1278
0
        break;
1279
0
    case '\\':
1280
0
        temp.push_back('\\');
1281
0
        ++cs;
1282
0
        break;
1283
0
    case '/':
1284
0
        temp.push_back('/');
1285
0
        ++cs;
1286
0
        break;
1287
0
    case 'b':
1288
0
        temp.push_back('\x08');
1289
0
        ++cs;
1290
0
        break;
1291
0
    case 'f':
1292
0
        temp.push_back('\x0c');
1293
0
        ++cs;
1294
0
        break;
1295
0
    case 'n':
1296
0
        temp.push_back('\x0a');
1297
0
        ++cs;
1298
0
        break;
1299
0
    case 'r':
1300
0
        temp.push_back('\x0d');
1301
0
        ++cs;
1302
0
        break;
1303
0
    case 't':
1304
0
        temp.push_back('\x09');
1305
0
        ++cs;
1306
0
        break;
1307
0
    case 'u':
1308
        // utf16 escape
1309
        //
1310
        // fast path only when the buffer
1311
        // is large enough for 2 surrogates
1312
0
        if(BOOST_JSON_LIKELY(cs.remain() > 10))
1313
0
        {
1314
            // KRYSTIAN TODO: this could be done
1315
            // with fewer instructions
1316
0
            digit = detail::load_little_endian<4>(
1317
0
                cs.begin() + 1);
1318
0
            int d4 = detail::hex_digit(static_cast<
1319
0
                unsigned char>(digit >> 24));
1320
0
            int d3 = detail::hex_digit(static_cast<
1321
0
                unsigned char>(digit >> 16));
1322
0
            int d2 = detail::hex_digit(static_cast<
1323
0
                unsigned char>(digit >> 8));
1324
0
            int d1 = detail::hex_digit(static_cast<
1325
0
                unsigned char>(digit));
1326
0
            if(BOOST_JSON_UNLIKELY(
1327
0
                (d1 | d2 | d3 | d4) == -1))
1328
0
            {
1329
0
                if(d1 != -1)
1330
0
                    ++cs;
1331
0
                if(d2 != -1)
1332
0
                    ++cs;
1333
0
                if(d3 != -1)
1334
0
                    ++cs;
1335
0
                BOOST_STATIC_CONSTEXPR source_location loc
1336
0
                    = BOOST_CURRENT_LOCATION;
1337
0
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1338
0
            }
1339
            // 32 bit unicode scalar value
1340
0
            unsigned const u1 =
1341
0
                (d1 << 12) + (d2 << 8) +
1342
0
                (d3 << 4) + d4;
1343
            // valid unicode scalar values are
1344
            // [0, D7FF] and [E000, 10FFFF]
1345
            // values within this range are valid utf-8
1346
            // code points and invalid leading surrogates.
1347
0
            if(BOOST_JSON_LIKELY(
1348
0
                u1 < 0xd800 || u1 > 0xdfff))
1349
0
            {
1350
0
                cs += 5;
1351
0
                temp.append_utf8(u1);
1352
0
                break;
1353
0
            }
1354
0
            if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1355
0
            {
1356
0
                BOOST_STATIC_CONSTEXPR source_location loc
1357
0
                    = BOOST_CURRENT_LOCATION;
1358
0
                return fail(cs.begin(), error::illegal_leading_surrogate,
1359
0
                    &loc);
1360
0
            }
1361
0
            cs += 5;
1362
            // KRYSTIAN TODO: this can be a two byte load
1363
            // and a single comparison. We lose error information,
1364
            // but it's faster.
1365
0
            if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1366
0
            {
1367
0
                BOOST_STATIC_CONSTEXPR source_location loc
1368
0
                    = BOOST_CURRENT_LOCATION;
1369
0
                return fail(cs.begin(), error::syntax, &loc);
1370
0
            }
1371
0
            ++cs;
1372
0
            if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1373
0
            {
1374
0
                BOOST_STATIC_CONSTEXPR source_location loc
1375
0
                    = BOOST_CURRENT_LOCATION;
1376
0
                return fail(cs.begin(), error::syntax, &loc);
1377
0
            }
1378
0
            ++cs;
1379
0
            digit = detail::load_little_endian<4>(cs.begin());
1380
0
            d4 = detail::hex_digit(static_cast<
1381
0
                unsigned char>(digit >> 24));
1382
0
            d3 = detail::hex_digit(static_cast<
1383
0
                unsigned char>(digit >> 16));
1384
0
            d2 = detail::hex_digit(static_cast<
1385
0
                unsigned char>(digit >> 8));
1386
0
            d1 = detail::hex_digit(static_cast<
1387
0
                unsigned char>(digit));
1388
0
            if(BOOST_JSON_UNLIKELY(
1389
0
                (d1 | d2 | d3 | d4) == -1))
1390
0
            {
1391
0
                if(d1 != -1)
1392
0
                    ++cs;
1393
0
                if(d2 != -1)
1394
0
                    ++cs;
1395
0
                if(d3 != -1)
1396
0
                    ++cs;
1397
0
                BOOST_STATIC_CONSTEXPR source_location loc
1398
0
                    = BOOST_CURRENT_LOCATION;
1399
0
                return fail(cs.begin(), error::expected_hex_digit, &loc);
1400
0
            }
1401
0
            unsigned const u2 =
1402
0
                (d1 << 12) + (d2 << 8) +
1403
0
                (d3 << 4) + d4;
1404
            // valid trailing surrogates are [DC00, DFFF]
1405
0
            if(BOOST_JSON_UNLIKELY(
1406
0
                u2 < 0xdc00 || u2 > 0xdfff))
1407
0
            {
1408
0
                BOOST_STATIC_CONSTEXPR source_location loc
1409
0
                    = BOOST_CURRENT_LOCATION;
1410
0
                return fail(cs.begin(), error::illegal_trailing_surrogate,
1411
0
                    &loc);
1412
0
            }
1413
0
            cs += 4;
1414
0
            unsigned cp =
1415
0
                ((u1 - 0xd800) << 10) +
1416
0
                ((u2 - 0xdc00)) +
1417
0
                    0x10000;
1418
            // utf-16 surrogate pair
1419
0
            temp.append_utf8(cp);
1420
0
            break;
1421
0
        }
1422
        // flush
1423
0
        if(BOOST_JSON_LIKELY(! temp.empty()))
1424
0
        {
1425
0
            BOOST_ASSERT(total <= max_size);
1426
0
            if(BOOST_JSON_UNLIKELY(
1427
0
                temp.size() > max_size - total))
1428
0
            {
1429
0
                BOOST_STATIC_CONSTEXPR source_location loc
1430
0
                    = BOOST_CURRENT_LOCATION;
1431
0
                return fail(cs.begin(), ev_too_large, &loc);
1432
0
            }
1433
0
            total += temp.size();
1434
0
            {
1435
0
                bool r = is_key
1436
0
                    ? h_.on_key_part(temp.get(), total, ec_)
1437
0
                    : h_.on_string_part(temp.get(), total, ec_);
1438
1439
0
                if(BOOST_JSON_UNLIKELY(!r))
1440
0
                {
1441
0
                    return fail(cs.begin());
1442
0
                }
1443
0
            }
1444
0
            temp.clear();
1445
0
            cs.clip(temp.max_size());
1446
0
        }
1447
0
        ++cs;
1448
        // utf-16 escape
1449
18
do_str4:
1450
18
        if(BOOST_JSON_UNLIKELY(! cs))
1451
18
            return maybe_suspend(cs.begin(), state::str4, total);
1452
0
        digit = detail::hex_digit(*cs);
1453
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1454
0
        {
1455
0
            BOOST_STATIC_CONSTEXPR source_location loc
1456
0
                = BOOST_CURRENT_LOCATION;
1457
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1458
0
        }
1459
0
        ++cs;
1460
0
        u1_ = digit << 12;
1461
16
do_str5:
1462
16
        if(BOOST_JSON_UNLIKELY(! cs))
1463
16
            return maybe_suspend(cs.begin(), state::str5, total);
1464
0
        digit = detail::hex_digit(*cs);
1465
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1466
0
        {
1467
0
            BOOST_STATIC_CONSTEXPR source_location loc
1468
0
                = BOOST_CURRENT_LOCATION;
1469
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1470
0
        }
1471
0
        ++cs;
1472
0
        u1_ += digit << 8;
1473
15
do_str6:
1474
15
        if(BOOST_JSON_UNLIKELY(! cs))
1475
15
            return maybe_suspend(cs.begin(), state::str6, total);
1476
0
        digit = detail::hex_digit(*cs);
1477
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1478
0
        {
1479
0
            BOOST_STATIC_CONSTEXPR source_location loc
1480
0
                = BOOST_CURRENT_LOCATION;
1481
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1482
0
        }
1483
0
        ++cs;
1484
0
        u1_ += digit << 4;
1485
19
do_str7:
1486
19
        if(BOOST_JSON_UNLIKELY(! cs))
1487
19
            return maybe_suspend(cs.begin(), state::str7, total);
1488
0
        digit = detail::hex_digit(*cs);
1489
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1490
0
        {
1491
0
            BOOST_STATIC_CONSTEXPR source_location loc
1492
0
                = BOOST_CURRENT_LOCATION;
1493
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1494
0
        }
1495
0
        ++cs;
1496
0
        u1_ += digit;
1497
0
        if(BOOST_JSON_LIKELY(
1498
0
            u1_ < 0xd800 || u1_ > 0xdfff))
1499
0
        {
1500
0
            BOOST_ASSERT(temp.empty());
1501
            // utf-8 codepoint
1502
0
            temp.append_utf8(u1_);
1503
0
            break;
1504
0
        }
1505
0
        if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1506
0
        {
1507
0
            BOOST_STATIC_CONSTEXPR source_location loc
1508
0
                = BOOST_CURRENT_LOCATION;
1509
0
            return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1510
0
        }
1511
12
do_sur1:
1512
12
        if(BOOST_JSON_UNLIKELY(! cs))
1513
12
            return maybe_suspend(cs.begin(), state::sur1, total);
1514
0
        if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1515
0
        {
1516
0
            BOOST_STATIC_CONSTEXPR source_location loc
1517
0
                = BOOST_CURRENT_LOCATION;
1518
0
            return fail(cs.begin(), error::syntax, &loc);
1519
0
        }
1520
0
        ++cs;
1521
2
do_sur2:
1522
2
        if(BOOST_JSON_UNLIKELY(! cs))
1523
2
            return maybe_suspend(cs.begin(), state::sur2, total);
1524
0
        if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1525
0
        {
1526
0
            BOOST_STATIC_CONSTEXPR source_location loc
1527
0
                = BOOST_CURRENT_LOCATION;
1528
0
            return fail(cs.begin(), error::syntax, &loc);
1529
0
        }
1530
0
        ++cs;
1531
3
do_sur3:
1532
3
        if(BOOST_JSON_UNLIKELY(! cs))
1533
3
            return maybe_suspend(cs.begin(), state::sur3, total);
1534
0
        digit = detail::hex_digit(*cs);
1535
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1536
0
        {
1537
0
            BOOST_STATIC_CONSTEXPR source_location loc
1538
0
                = BOOST_CURRENT_LOCATION;
1539
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1540
0
        }
1541
0
        ++cs;
1542
0
        u2_ = digit << 12;
1543
11
do_sur4:
1544
11
        if(BOOST_JSON_UNLIKELY(! cs))
1545
11
            return maybe_suspend(cs.begin(), state::sur4, total);
1546
0
        digit = detail::hex_digit(*cs);
1547
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1548
0
        {
1549
0
            BOOST_STATIC_CONSTEXPR source_location loc
1550
0
                = BOOST_CURRENT_LOCATION;
1551
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1552
0
        }
1553
0
        ++cs;
1554
0
        u2_ += digit << 8;
1555
7
do_sur5:
1556
7
        if(BOOST_JSON_UNLIKELY(! cs))
1557
7
            return maybe_suspend(cs.begin(), state::sur5, total);
1558
0
        digit = detail::hex_digit(*cs);
1559
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1560
0
        {
1561
0
            BOOST_STATIC_CONSTEXPR source_location loc
1562
0
                = BOOST_CURRENT_LOCATION;
1563
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1564
0
        }
1565
0
        ++cs;
1566
0
        u2_ += digit << 4;
1567
16
do_sur6:
1568
16
        if(BOOST_JSON_UNLIKELY(! cs))
1569
16
            return maybe_suspend(cs.begin(), state::sur6, total);
1570
0
        digit = detail::hex_digit(*cs);
1571
0
        if(BOOST_JSON_UNLIKELY(digit == -1))
1572
0
        {
1573
0
            BOOST_STATIC_CONSTEXPR source_location loc
1574
0
                = BOOST_CURRENT_LOCATION;
1575
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1576
0
        }
1577
0
        ++cs;
1578
0
        u2_ += digit;
1579
0
        if(BOOST_JSON_UNLIKELY(
1580
0
            u2_ < 0xdc00 || u2_ > 0xdfff))
1581
0
        {
1582
0
            BOOST_STATIC_CONSTEXPR source_location loc
1583
0
                = BOOST_CURRENT_LOCATION;
1584
0
            return fail(cs.begin(), error::expected_hex_digit, &loc);
1585
0
        }
1586
0
        unsigned cp =
1587
0
            ((u1_ - 0xd800) << 10) +
1588
0
            ((u2_ - 0xdc00)) +
1589
0
                0x10000;
1590
0
        BOOST_ASSERT(temp.empty());
1591
        // utf-16 surrogate pair
1592
0
        temp.append_utf8(cp);
1593
0
    }
1594
292
do_str2:
1595
    // KRYSTIAN TODO: we can append the characters
1596
    // all at once instead of one at a time
1597
292
    for(;;)
1598
292
    {
1599
292
        if(BOOST_JSON_UNLIKELY(! cs || temp.capacity() == 0 ))
1600
292
        {
1601
            // flush
1602
292
            if(BOOST_JSON_LIKELY(! temp.empty()))
1603
0
            {
1604
0
                BOOST_ASSERT(total <= max_size);
1605
0
                if(BOOST_JSON_UNLIKELY(
1606
0
                    temp.size() > max_size - total))
1607
0
                {
1608
0
                    BOOST_STATIC_CONSTEXPR source_location loc
1609
0
                        = BOOST_CURRENT_LOCATION;
1610
0
                    return fail(cs.begin(), ev_too_large, &loc);
1611
0
                }
1612
0
                total += temp.size();
1613
0
                {
1614
0
                    bool r = is_key
1615
0
                        ? h_.on_key_part(temp.get(), total, ec_)
1616
0
                        : h_.on_string_part(temp.get(), total, ec_);
1617
1618
0
                    if(BOOST_JSON_UNLIKELY(!r))
1619
0
                    {
1620
0
                        return fail(cs.begin());
1621
0
                    }
1622
0
                }
1623
0
                temp.clear();
1624
0
            }
1625
292
            cs.clip(temp.max_size());
1626
292
            if(BOOST_JSON_UNLIKELY(! cs))
1627
292
                return maybe_suspend(cs.begin(), state::str2, total);
1628
292
        }
1629
0
        c = *cs;
1630
0
        if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
1631
0
        {
1632
0
            BOOST_ASSERT(total <= max_size);
1633
0
            if(BOOST_JSON_UNLIKELY(
1634
0
                temp.size() > max_size - total))
1635
0
            {
1636
0
                BOOST_STATIC_CONSTEXPR source_location loc
1637
0
                    = BOOST_CURRENT_LOCATION;
1638
0
                return fail(cs.begin(), ev_too_large, &loc);
1639
0
            }
1640
0
            total += temp.size();
1641
0
            {
1642
0
                bool r = is_key
1643
0
                    ? h_.on_key(temp.get(), total, ec_)
1644
0
                    : h_.on_string(temp.get(), total, ec_);
1645
1646
0
                if(BOOST_JSON_UNLIKELY(!r))
1647
0
                {
1648
0
                    return fail(cs.begin());
1649
0
                }
1650
0
            }
1651
0
            ++cs;
1652
0
            return cs.begin();
1653
0
        }
1654
0
        else if((c & 0x80) && !allow_bad_utf8)
1655
0
        {
1656
0
            seq_.save(cs.begin(), cs.remain());
1657
0
            if(BOOST_JSON_UNLIKELY(! seq_.complete()))
1658
0
            {
1659
0
                if(BOOST_JSON_LIKELY(! temp.empty()))
1660
0
                {
1661
0
                    BOOST_ASSERT(total <= max_size);
1662
0
                    if(BOOST_JSON_UNLIKELY(
1663
0
                        temp.size() > max_size - total))
1664
0
                    {
1665
0
                        BOOST_STATIC_CONSTEXPR source_location loc
1666
0
                            = BOOST_CURRENT_LOCATION;
1667
0
                        return fail(cs.begin(), ev_too_large, &loc);
1668
0
                    }
1669
0
                    total += temp.size();
1670
0
                    {
1671
0
                        bool r = is_key
1672
0
                            ? h_.on_key_part(temp.get(), total, ec_)
1673
0
                            : h_.on_string_part(temp.get(), total, ec_);
1674
1675
0
                        if(BOOST_JSON_UNLIKELY(!r))
1676
0
                        {
1677
0
                            return fail(cs.begin());
1678
0
                        }
1679
0
                    }
1680
0
                    temp.clear();
1681
0
                }
1682
0
                cs = cs.end();
1683
                // ensure there is room for the saved byte sequence
1684
0
                cs.clip(temp.max_size() - seq_.length());
1685
0
                goto do_str8;
1686
0
            }
1687
0
            if(BOOST_JSON_UNLIKELY(! seq_.valid()))
1688
0
            {
1689
0
                BOOST_STATIC_CONSTEXPR source_location loc
1690
0
                    = BOOST_CURRENT_LOCATION;
1691
0
                return fail(cs.begin(), error::syntax, &loc);
1692
0
            }
1693
0
            temp.append(seq_.data(), seq_.length());
1694
0
            cs += seq_.length();
1695
0
            continue;
1696
0
        }
1697
0
        else if(BOOST_JSON_LIKELY(c == '\\'))
1698
0
        {
1699
0
            ++cs;
1700
0
            goto do_str3;
1701
0
        }
1702
0
        else if(BOOST_JSON_UNLIKELY(
1703
0
            detail::is_control(c)))
1704
0
        {
1705
0
            BOOST_STATIC_CONSTEXPR source_location loc
1706
0
                = BOOST_CURRENT_LOCATION;
1707
0
            return fail(cs.begin(), error::syntax, &loc);
1708
0
        }
1709
0
        temp.push_back(c);
1710
0
        ++cs;
1711
0
    }
1712
79
do_str8:
1713
79