TLA Line data Source code
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/detail/literals.hpp>
16 : #include <boost/json/basic_parser.hpp>
17 : #include <boost/json/error.hpp>
18 : #include <boost/json/detail/buffer.hpp>
19 : #include <boost/json/detail/charconv/from_chars.hpp>
20 : #include <boost/json/detail/sse2.hpp>
21 : #include <boost/mp11/algorithm.hpp>
22 : #include <boost/mp11/integral.hpp>
23 : #include <cmath>
24 : #include <limits>
25 : #include <cstring>
26 :
27 : #ifdef _MSC_VER
28 : #pragma warning(push)
29 : #pragma warning(disable: 4702) // unreachable code
30 : #pragma warning(disable: 4127) // conditional expression is constant
31 : #endif
32 :
33 : /* This file must be manually included to get the
34 : function template definitions for basic_parser.
35 : */
36 :
37 : /* Reference:
38 :
39 : https://www.json.org/
40 :
41 : RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
42 : https://tools.ietf.org/html/rfc7159
43 :
44 : https://ampl.com/netlib/fp/dtoa.c
45 : */
46 :
47 : #ifndef BOOST_JSON_DOCS
48 :
49 : namespace boost {
50 : namespace json {
51 : namespace detail {
52 :
53 : inline
54 : double
55 HIT 1042951 : pow10(int exp) noexcept
56 : {
57 : static double const tab[618] = {
58 : 1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
59 :
60 : 1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
61 : 1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
62 : 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
63 : 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
64 : 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
65 : 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
66 : 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
67 : 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
68 : 1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
69 : 1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
70 :
71 : 1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
72 : 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
73 : 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
74 : 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
75 : 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
76 : 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
77 : 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
78 : 1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
79 : 1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
80 : 1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
81 :
82 : 1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
83 : 1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
84 : 1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
85 : 1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
86 : 1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
87 : 1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
88 : 1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
89 : 1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
90 : 1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
91 : 1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
92 :
93 : 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
94 : 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
95 : 1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
96 : 1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
97 : 1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
98 : 1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
99 : 1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
100 : 1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
101 : 1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
102 : 1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
103 :
104 : 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
105 : 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
106 : 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
107 : 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
108 : 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
109 : 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
110 : 1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
111 : 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
112 : 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
113 : 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
114 :
115 : 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
116 : 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
117 : 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
118 : 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
119 : 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
120 : 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
121 : 1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
122 : 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
123 : 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
124 : 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
125 :
126 : 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
127 :
128 1042951 : if( exp > 308 )
129 : {
130 341 : return std::numeric_limits<double>::infinity();
131 : }
132 1042610 : else if( exp < -308 )
133 : {
134 : // due to the way pow10 is used by dec_to_float,
135 : // we can afford to return 0.0 here
136 151 : return 0.0;
137 : }
138 : else
139 : {
140 1042459 : exp += 308;
141 1042459 : BOOST_ASSERT(exp >= 0 && exp < 618);
142 1042459 : return tab[exp];
143 : }
144 : }
145 :
146 : inline
147 : double
148 1042951 : dec_to_float(
149 : std::uint64_t m,
150 : std::int32_t e,
151 : bool neg) noexcept
152 : {
153 : // convert to double explicitly to silence warnings
154 1042951 : double x = static_cast<double>(m);
155 1042951 : if(neg)
156 17062 : x = -x;
157 :
158 1042951 : if(e < -305)
159 : {
160 5269 : x *= 1e-305 ;
161 5269 : e += 305;
162 : }
163 :
164 1042951 : if(e >= -22 && e < 0)
165 59279 : return x / pow10(-e);
166 :
167 983672 : return x * pow10(e);
168 : }
169 :
170 : inline
171 : bool
172 : is_control(char c) noexcept
173 : {
174 : return static_cast<unsigned char>(c) < 32;
175 : }
176 :
177 : inline
178 : int
179 66931 : hex_digit(unsigned char c) noexcept
180 : {
181 : // by Peter Dimov
182 66931 : if( c >= '0' && c <= '9' )
183 35759 : return c - '0';
184 31172 : c &= ~0x20;
185 31172 : if( c >= 'A' && c <= 'F' )
186 30562 : return 10 + c - 'A';
187 610 : return -1;
188 : }
189 :
190 : } // detail
191 :
192 : //----------------------------------------------------------
193 :
194 : template< class Handler >
195 : template< bool StackEmpty_, char First_ >
196 : struct basic_parser<Handler>::
197 : parse_number_helper
198 : {
199 : basic_parser* parser;
200 : char const* p;
201 :
202 : template< std::size_t N >
203 : char const*
204 2110611 : operator()( mp11::mp_size_t<N> ) const
205 : {
206 4215781 : return parser->parse_number(
207 2110611 : p,
208 : std::integral_constant<bool, StackEmpty_>(),
209 : std::integral_constant<char, First_>(),
210 : std::integral_constant<
211 2105171 : number_precision, static_cast<number_precision>(N)>() );
212 : }
213 :
214 : char const*
215 16277 : operator()(
216 : mp11::mp_size_t<static_cast<std::size_t>(number_precision::none)> )
217 : const
218 : {
219 32554 : return parser->skip_number(
220 16277 : p,
221 : std::integral_constant<bool, StackEmpty_>(),
222 16277 : std::integral_constant<char, First_>() );
223 : }
224 : };
225 :
226 : //----------------------------------------------------------
227 :
228 : template<class Handler>
229 : void
230 210572 : basic_parser<Handler>::
231 : reserve()
232 : {
233 210572 : if(BOOST_JSON_LIKELY(
234 : ! st_.empty()))
235 37469 : return;
236 : // Reserve the largest stack we need,
237 : // to avoid reallocation during suspend.
238 346206 : st_.reserve(
239 : sizeof(state) + // document parsing state
240 : (sizeof(state) +
241 173103 : sizeof(std::size_t)) * depth() + // array and object state + size
242 : sizeof(state) + // value parsing state
243 : sizeof(std::size_t) + // string size
244 : sizeof(state)); // comment state
245 : }
246 :
247 : //----------------------------------------------------------
248 : //
249 : // The sentinel value is returned by parse functions
250 : // to indicate that the parser failed, or suspended.
251 : // this is used as it is distinct from all valid values
252 : // for data in write
253 :
254 : template<class Handler>
255 : const char*
256 5341073 : basic_parser<Handler>::
257 : sentinel()
258 : {
259 : // the "+1" ensures that the returned pointer is unique even if
260 : // the given input buffer borders on this object
261 : return reinterpret_cast<
262 5341073 : const char*>(this) + 1;
263 : }
264 :
265 : template<class Handler>
266 : bool
267 2459881 : basic_parser<Handler>::
268 : incomplete(
269 : const detail::const_stream_wrapper& cs)
270 : {
271 2459881 : return cs.begin() == sentinel();
272 : }
273 :
274 : //----------------------------------------------------------
275 : //
276 : // These functions are declared with the BOOST_NOINLINE
277 : // attribute to avoid polluting the parsers hot-path.
278 : // They return the canary value to indicate suspension
279 : // or failure.
280 :
281 : template<class Handler>
282 : const char*
283 : basic_parser<Handler>::
284 : suspend_or_fail(state st)
285 : {
286 : if(BOOST_JSON_LIKELY(
287 : ! ec_ && more_))
288 : {
289 : // suspend
290 : reserve();
291 : st_.push_unchecked(st);
292 : }
293 : return sentinel();
294 : }
295 :
296 : template<class Handler>
297 : const char*
298 56176 : basic_parser<Handler>::
299 : suspend_or_fail(
300 : state st,
301 : std::size_t n)
302 : {
303 56176 : if(BOOST_JSON_LIKELY(
304 : ! ec_ && more_))
305 : {
306 : // suspend
307 35861 : reserve();
308 35861 : st_.push_unchecked(n);
309 35861 : st_.push_unchecked(st);
310 : }
311 56176 : return sentinel();
312 : }
313 :
314 :
315 : template<class Handler>
316 : const char*
317 19005 : basic_parser<Handler>::
318 : fail(const char* p) noexcept
319 : {
320 19005 : BOOST_ASSERT( p != sentinel() );
321 19005 : end_ = p;
322 19005 : return sentinel();
323 : }
324 :
325 : template<class Handler>
326 : const char*
327 7774 : basic_parser<Handler>::
328 : fail(
329 : const char* p,
330 : error ev,
331 : source_location const* loc) noexcept
332 : {
333 7774 : BOOST_ASSERT( p != sentinel() );
334 7774 : end_ = p;
335 7774 : ec_.assign(ev, loc);
336 7774 : return sentinel();
337 : }
338 :
339 : template<class Handler>
340 : const char*
341 11289 : basic_parser<Handler>::
342 : maybe_suspend(
343 : const char* p,
344 : state st)
345 : {
346 11289 : if( p != sentinel() )
347 9424 : end_ = p;
348 11289 : if(BOOST_JSON_LIKELY(more_))
349 : {
350 : // suspend
351 11027 : reserve();
352 11027 : st_.push_unchecked(st);
353 : }
354 11289 : return sentinel();
355 : }
356 :
357 : template<class Handler>
358 : const char*
359 38234 : basic_parser<Handler>::
360 : maybe_suspend(
361 : const char* p,
362 : state st,
363 : std::size_t n)
364 : {
365 38234 : BOOST_ASSERT( p != sentinel() );
366 38234 : end_ = p;
367 38234 : if(BOOST_JSON_LIKELY(more_))
368 : {
369 : // suspend
370 37833 : reserve();
371 37833 : st_.push_unchecked(n);
372 37833 : st_.push_unchecked(st);
373 : }
374 38234 : return sentinel();
375 : }
376 :
377 : template<class Handler>
378 : const char*
379 1123 : basic_parser<Handler>::
380 : maybe_suspend(
381 : const char* p,
382 : state st,
383 : const number& num)
384 : {
385 1123 : BOOST_ASSERT( p != sentinel() );
386 1123 : end_ = p;
387 1123 : if(BOOST_JSON_LIKELY(more_))
388 : {
389 : // suspend
390 1123 : num_ = num;
391 1123 : reserve();
392 1123 : st_.push_unchecked(st);;
393 : }
394 1123 : return sentinel();
395 : }
396 :
397 : template<class Handler>
398 : const char*
399 88657 : basic_parser<Handler>::
400 : suspend(
401 : const char* p,
402 : state st)
403 : {
404 88657 : BOOST_ASSERT( p != sentinel() );
405 88657 : end_ = p;
406 : // suspend
407 88657 : reserve();
408 88657 : st_.push_unchecked(st);
409 88657 : return sentinel();
410 : }
411 :
412 : template<class Handler>
413 : const char*
414 36071 : basic_parser<Handler>::
415 : suspend(
416 : const char* p,
417 : state st,
418 : const number& num)
419 : {
420 36071 : BOOST_ASSERT( p != sentinel() );
421 36071 : end_ = p;
422 : // suspend
423 36071 : num_ = num;
424 36071 : reserve();
425 36071 : st_.push_unchecked(st);
426 36071 : return sentinel();
427 : }
428 :
429 : template<class Handler>
430 : template<
431 : bool StackEmpty_/*,
432 : bool Terminal_*/>
433 : const char*
434 21737 : basic_parser<Handler>::
435 : parse_comment(const char* p,
436 : std::integral_constant<bool, StackEmpty_> stack_empty,
437 : /*std::integral_constant<bool, Terminal_>*/ bool terminal)
438 : {
439 21737 : detail::const_stream_wrapper cs(p, end_);
440 21737 : const char* start = cs.begin();
441 : std::size_t remain;
442 21737 : if(! stack_empty && ! st_.empty())
443 : {
444 : state st;
445 3507 : st_.pop(st);
446 3507 : switch(st)
447 : {
448 MIS 0 : default: BOOST_JSON_UNREACHABLE();
449 HIT 534 : case state::com1: goto do_com1;
450 2319 : case state::com2: goto do_com2;
451 438 : case state::com3: goto do_com3;
452 216 : case state::com4: goto do_com4;
453 : }
454 : }
455 18230 : BOOST_ASSERT(*cs == '/');
456 18230 : ++cs;
457 18764 : do_com1:
458 18764 : if(BOOST_JSON_UNLIKELY(! cs))
459 551 : return maybe_suspend(cs.begin(), state::com1);
460 18213 : switch(*cs)
461 : {
462 5 : default:
463 : {
464 : BOOST_STATIC_CONSTEXPR source_location loc
465 : = BOOST_CURRENT_LOCATION;
466 5 : return fail(cs.begin(), error::syntax, &loc);
467 : }
468 10524 : case '/':
469 10524 : ++cs;
470 12843 : do_com2:
471 : // KRYSTIAN TODO: this is a mess, we have to fix this
472 12843 : remain = cs.remain();
473 25686 : cs = remain ? static_cast<const char*>(
474 12843 : std::memchr(cs.begin(), '\n', remain)) : sentinel();
475 12843 : if(! cs.begin())
476 2143 : cs = sentinel();
477 12843 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
478 : {
479 : // if the doc does not terminate
480 : // with a newline, treat it as the
481 : // end of the comment
482 2568 : if(terminal && ! more_)
483 : {
484 39 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
485 : {start, cs.remain(start)}, ec_)))
486 2 : return fail(cs.end());
487 35 : return cs.end();
488 : }
489 2529 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
490 : {start, cs.remain(start)}, ec_)))
491 95 : return fail(cs.end());
492 2339 : if(terminal)
493 106 : return suspend(cs.end(), state::com2);
494 2233 : return maybe_suspend(cs.end(), state::com2);
495 : }
496 10275 : break;
497 1684 : case '*':
498 : do
499 : {
500 9368 : ++cs;
501 9806 : do_com3:
502 : // KRYSTIAN TODO: this is a mess, we have to fix this
503 9806 : remain = cs.remain();
504 19612 : cs = remain ? static_cast<const char*>(
505 9806 : std::memchr(cs.begin(), '*', remain)) : sentinel();
506 9806 : if(! cs.begin())
507 242 : cs = sentinel();
508 : // stopped inside a c comment
509 9806 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
510 : {
511 503 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
512 : {start, cs.remain(start)}, ec_)))
513 30 : return fail(cs.end());
514 443 : return maybe_suspend(cs.end(), state::com3);
515 : }
516 : // found a asterisk, check if the next char is a slash
517 9303 : ++cs;
518 9519 : do_com4:
519 9519 : if(BOOST_JSON_UNLIKELY(! cs))
520 : {
521 259 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
522 : {start, cs.used(start)}, ec_)))
523 18 : return fail(cs.begin());
524 223 : return maybe_suspend(cs.begin(), state::com4);
525 : }
526 : }
527 9260 : while(*cs != '/');
528 : }
529 17851 : ++cs;
530 17851 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
531 : {start, cs.used(start)}, ec_)))
532 964 : return fail(cs.begin());
533 15923 : return cs.begin();
534 : }
535 :
536 : template<class Handler>
537 : template<bool StackEmpty_>
538 : const char*
539 2318439 : basic_parser<Handler>::
540 : parse_document(const char* p,
541 : std::integral_constant<bool, StackEmpty_> stack_empty)
542 : {
543 2318439 : detail::const_stream_wrapper cs(p, end_);
544 2318439 : if(! stack_empty && ! st_.empty())
545 : {
546 : state st;
547 169624 : st_.peek(st);
548 169624 : switch(st)
549 : {
550 83559 : default: goto do_doc2;
551 601 : case state::doc1:
552 601 : st_.pop(st);
553 601 : goto do_doc1;
554 85244 : case state::doc3:
555 85244 : st_.pop(st);
556 85244 : goto do_doc3;
557 220 : case state::com1: case state::com2:
558 : case state::com3: case state::com4:
559 220 : goto do_doc4;
560 : }
561 : }
562 2148815 : do_doc1:
563 2149416 : cs = detail::count_whitespace(cs.begin(), cs.end());
564 2149416 : if(BOOST_JSON_UNLIKELY(! cs))
565 633 : return maybe_suspend(cs.begin(), state::doc1);
566 2148783 : do_doc2:
567 2232342 : switch(+opt_.allow_comments |
568 2232342 : (opt_.allow_trailing_commas << 1) |
569 2232342 : (opt_.allow_invalid_utf8 << 2))
570 : {
571 : // no extensions
572 2208660 : default:
573 2208660 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
574 2193502 : break;
575 : // comments
576 13551 : case 1:
577 13551 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
578 11288 : break;
579 : // trailing
580 6710 : case 2:
581 6710 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
582 5117 : break;
583 : // comments & trailing
584 761 : case 3:
585 761 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
586 761 : break;
587 : // skip validation
588 760 : case 4:
589 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
590 760 : break;
591 : // comments & skip validation
592 760 : case 5:
593 760 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
594 760 : break;
595 : // trailing & skip validation
596 760 : case 6:
597 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
598 760 : break;
599 : // comments & trailing & skip validation
600 380 : case 7:
601 380 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
602 380 : break;
603 : }
604 2213328 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
605 : // the appropriate state has already been pushed into stack
606 110765 : return sentinel();
607 2102563 : do_doc3:
608 2188139 : cs = detail::count_whitespace(cs.begin(), cs.end());
609 2188139 : if(BOOST_JSON_UNLIKELY(! cs))
610 : {
611 2185541 : if(more_)
612 88551 : return suspend(cs.begin(), state::doc3);
613 : }
614 2598 : else if(opt_.allow_comments && *cs == '/')
615 : {
616 536 : do_doc4:
617 756 : cs = parse_comment(cs.begin(), stack_empty, std::true_type());
618 671 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
619 339 : return sentinel();
620 332 : goto do_doc3;
621 : }
622 2099052 : return cs.begin();
623 : }
624 :
625 : template<class Handler>
626 : template<
627 : bool StackEmpty_,
628 : bool AllowComments_/*,
629 : bool AllowTrailing_,
630 : bool AllowBadUTF8_*/>
631 : const char*
632 2349972 : basic_parser<Handler>::
633 : parse_value(const char* p,
634 : std::integral_constant<bool, StackEmpty_> stack_empty,
635 : std::integral_constant<bool, AllowComments_> allow_comments,
636 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
637 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
638 : bool allow_bad_utf16)
639 : {
640 2349972 : if(stack_empty || st_.empty())
641 : {
642 2248027 : loop:
643 2252943 : switch(*p)
644 : {
645 22753 : case '0':
646 22753 : return mp11::mp_with_index<3>(
647 22753 : static_cast<unsigned char>(opt_.numbers),
648 22092 : parse_number_helper<true, '0'>{ this, p });
649 25178 : case '-':
650 25178 : return mp11::mp_with_index<3>(
651 25178 : static_cast<unsigned char>(opt_.numbers),
652 24066 : parse_number_helper<true, '-'>{ this, p });
653 2041766 : case '1': case '2': case '3':
654 : case '4': case '5': case '6':
655 : case '7': case '8': case '9':
656 2041766 : return mp11::mp_with_index<3>(
657 2041766 : static_cast<unsigned char>(opt_.numbers),
658 2038922 : parse_number_helper<true, '+'>{ this, p });
659 11380 : case 'n':
660 11380 : return parse_literal( p, detail::literals_c<detail::literals::null>() );
661 664 : case 't':
662 664 : return parse_literal( p, detail::literals_c<detail::literals::true_>() );
663 722 : case 'f':
664 722 : return parse_literal( p, detail::literals_c<detail::literals::false_>() );
665 681 : case 'I':
666 681 : if( !opt_.allow_infinity_and_nan )
667 : {
668 : BOOST_STATIC_CONSTEXPR source_location loc
669 : = BOOST_CURRENT_LOCATION;
670 24 : return fail(p, error::syntax, &loc);
671 : }
672 657 : return parse_literal( p, detail::literals_c<detail::literals::infinity>() );
673 231 : case 'N':
674 231 : if( !opt_.allow_infinity_and_nan )
675 : {
676 : BOOST_STATIC_CONSTEXPR source_location loc
677 : = BOOST_CURRENT_LOCATION;
678 30 : return fail(p, error::syntax, &loc);
679 : }
680 201 : return parse_literal(p, detail::literals_c<detail::literals::nan>() );
681 47577 : case '"':
682 47577 : return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
683 20618 : case '[':
684 20618 : return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
685 74131 : case '{':
686 74131 : return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
687 6125 : case '/':
688 6125 : if(! allow_comments)
689 : {
690 : BOOST_STATIC_CONSTEXPR source_location loc
691 : = BOOST_CURRENT_LOCATION;
692 284 : return fail(p, error::syntax, &loc);
693 : }
694 5841 : p = parse_comment(p, stack_empty, std::false_type());
695 : // KRYSTIAN NOTE: incomplete takes const_stream, we either
696 : // can add an overload, change the existing one to take a pointer,
697 : // or just leave it as is
698 5605 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
699 591 : return maybe_suspend(p, state::val2);
700 : BOOST_FALLTHROUGH;
701 : case ' ':
702 : case '\t':
703 : case '\n':
704 : case '\r':
705 5026 : p = detail::count_whitespace(p, end_);
706 5026 : if(BOOST_JSON_UNLIKELY(p == end_))
707 110 : return maybe_suspend(p, state::val1);
708 4916 : goto loop;
709 1105 : default:
710 : {
711 : BOOST_STATIC_CONSTEXPR source_location loc
712 : = BOOST_CURRENT_LOCATION;
713 1105 : return fail(p, error::syntax, &loc);
714 : }
715 : }
716 : }
717 101945 : return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
718 : }
719 :
720 : template<class Handler>
721 : template<
722 : bool AllowComments_/*,
723 : bool AllowTrailing_,
724 : bool AllowBadUTF8_*/>
725 : const char*
726 101945 : basic_parser<Handler>::
727 : resume_value(const char* p,
728 : std::integral_constant<bool, AllowComments_> allow_comments,
729 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
730 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
731 : bool allow_bad_utf16)
732 : {
733 : state st;
734 101945 : st_.peek(st);
735 101945 : switch(st)
736 : {
737 MIS 0 : default: BOOST_JSON_UNREACHABLE();
738 HIT 1924 : case state::lit1:
739 1924 : return parse_literal(p, detail::literals_c<detail::literals::resume>() );
740 :
741 20259 : case state::str1: case state::str2:
742 : case state::str8:
743 20259 : return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
744 :
745 5730 : case state::arr1: case state::arr2:
746 : case state::arr3: case state::arr4:
747 : case state::arr5: case state::arr6:
748 5730 : return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
749 :
750 35058 : case state::obj1: case state::obj2:
751 : case state::obj3: case state::obj4:
752 : case state::obj5: case state::obj6:
753 : case state::obj7: case state::obj8:
754 : case state::obj9: case state::obj10:
755 : case state::obj11:
756 35058 : return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
757 :
758 37191 : case state::num1: case state::num2:
759 : case state::num3: case state::num4:
760 : case state::num5: case state::num6:
761 : case state::num7: case state::num8:
762 : case state::exp1: case state::exp2:
763 : case state::exp3:
764 37191 : return mp11::mp_with_index<3>(
765 37191 : static_cast<unsigned char>(opt_.numbers),
766 36368 : parse_number_helper<false, 0>{ this, p });
767 :
768 : // KRYSTIAN NOTE: these are special cases
769 108 : case state::val1:
770 : {
771 108 : st_.pop(st);
772 108 : BOOST_ASSERT(st_.empty());
773 108 : p = detail::count_whitespace(p, end_);
774 108 : if(BOOST_JSON_UNLIKELY(p == end_))
775 MIS 0 : return maybe_suspend(p, state::val1);
776 HIT 108 : return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
777 : }
778 :
779 1608 : case state::val2:
780 : {
781 1608 : st_.pop(st);
782 1608 : p = parse_comment(p, std::false_type(), std::false_type());
783 1590 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
784 1274 : return maybe_suspend(p, state::val2);
785 316 : if(BOOST_JSON_UNLIKELY( p == end_ ))
786 77 : return maybe_suspend(p, state::val3);
787 239 : BOOST_ASSERT(st_.empty());
788 239 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
789 : }
790 :
791 67 : case state::val3:
792 : {
793 67 : st_.pop(st);
794 67 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
795 : }
796 : }
797 : }
798 :
799 : template<class Handler>
800 : template<class Literal>
801 : const char*
802 16564 : basic_parser<Handler>::
803 : parse_literal(const char* p, Literal)
804 : {
805 : using L = detail::literals;
806 :
807 : std::size_t cur_lit;
808 : std::size_t offset;
809 :
810 16564 : detail::const_stream_wrapper cs(p, end_);
811 : BOOST_IF_CONSTEXPR( Literal::value != L::resume )
812 : {
813 13633 : constexpr std::size_t index = literal_index(Literal::value);
814 13633 : constexpr char const* literal = detail::literal_strings[index];
815 13633 : constexpr std::size_t sz = detail::literal_sizes[index];
816 :
817 13633 : if(BOOST_JSON_LIKELY( cs.remain() >= sz ))
818 : {
819 11983 : int const cmp = std::memcmp(cs.begin(), literal, sz);
820 11983 : if( cmp != 0 )
821 : {
822 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
823 197 : return fail(cs.begin(), error::syntax, &loc);
824 : }
825 :
826 : BOOST_IF_CONSTEXPR( Literal::value == L::null )
827 : {
828 10788 : if(BOOST_JSON_UNLIKELY(
829 : ! h_.on_null(ec_)))
830 161 : return fail(cs.begin());
831 : }
832 : else BOOST_IF_CONSTEXPR( Literal::value == L::true_ )
833 : {
834 384 : if(BOOST_JSON_UNLIKELY(
835 : ! h_.on_bool(true, ec_)))
836 14 : return fail(cs.begin());
837 : }
838 : else BOOST_IF_CONSTEXPR( Literal::value == L::false_ )
839 : {
840 406 : if(BOOST_JSON_UNLIKELY(
841 : ! h_.on_bool(false, ec_)))
842 13 : return fail(cs.begin());
843 : }
844 : else BOOST_IF_CONSTEXPR( Literal::value == L::infinity )
845 : {
846 103 : if(BOOST_JSON_UNLIKELY(
847 : ! h_.on_double(
848 : std::numeric_limits<double>::infinity(),
849 : string_view(literal, sz),
850 : ec_)))
851 13 : return fail(cs.begin());
852 : }
853 : else BOOST_IF_CONSTEXPR( Literal::value == L::neg_infinity )
854 : {
855 9 : if(BOOST_JSON_UNLIKELY(
856 : ! h_.on_double(
857 : -std::numeric_limits<double>::infinity(),
858 : string_view(literal, sz),
859 : ec_)))
860 1 : return fail(cs.begin());
861 : }
862 : else BOOST_IF_CONSTEXPR( Literal::value == L::nan )
863 : {
864 96 : if(BOOST_JSON_UNLIKELY(
865 : ! h_.on_double(
866 : std::numeric_limits<double>::quiet_NaN(),
867 : string_view(literal, sz),
868 : ec_)))
869 12 : return fail(cs.begin());
870 : }
871 : else
872 : {
873 : BOOST_JSON_UNREACHABLE();
874 : }
875 :
876 11362 : cs += sz;
877 11362 : return cs.begin();
878 : }
879 :
880 1650 : offset = 0;
881 1650 : cur_lit = index;
882 : }
883 : else
884 : {
885 : state st;
886 2931 : st_.pop(st);
887 2931 : BOOST_ASSERT( st == state::lit1 );
888 :
889 2931 : cur_lit = cur_lit_;
890 2931 : offset = lit_offset_;
891 : }
892 :
893 4581 : std::size_t const lit_size = detail::literal_sizes[cur_lit];
894 4581 : std::size_t const size = (std::min)( lit_size - offset, cs.remain() );
895 4581 : int cmp = 0;
896 4581 : if(BOOST_JSON_LIKELY( cs.begin() ))
897 4580 : cmp = std::memcmp(
898 4580 : cs.begin(), detail::literal_strings[cur_lit] + offset, size );
899 4581 : if( cmp != 0 )
900 : {
901 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
902 699 : return fail(cs.begin(), error::syntax, &loc);
903 : }
904 :
905 3882 : if(BOOST_JSON_UNLIKELY( offset + size < lit_size ))
906 : {
907 1990 : BOOST_ASSERT( cur_lit < 256 );
908 1990 : cur_lit_ = static_cast<unsigned char>( cur_lit );
909 1990 : BOOST_ASSERT( offset + size < 256 );
910 1990 : lit_offset_ = static_cast<unsigned char>( offset + size );
911 1990 : return maybe_suspend(cs.begin() + size, state::lit1);
912 : }
913 :
914 1892 : switch( static_cast<L>(cur_lit) )
915 : {
916 472 : case L::null:
917 472 : if(BOOST_JSON_UNLIKELY(
918 : ! h_.on_null(ec_)))
919 61 : return fail(cs.begin());
920 351 : break;
921 152 : case L::true_:
922 152 : if(BOOST_JSON_UNLIKELY(
923 : ! h_.on_bool(true, ec_)))
924 22 : return fail(cs.begin());
925 109 : break;
926 198 : case L::false_:
927 198 : if(BOOST_JSON_UNLIKELY(
928 : ! h_.on_bool(false, ec_)))
929 28 : return fail(cs.begin());
930 142 : break;
931 308 : case L::infinity:
932 308 : if(BOOST_JSON_UNLIKELY(
933 : ! h_.on_double(
934 : std::numeric_limits<double>::infinity(),
935 : string_view(
936 : detail::literal_strings[ literal_index(L::infinity) ],
937 : detail::literal_sizes[ literal_index(L::infinity) ]),
938 : ec_)))
939 49 : return fail(cs.begin());
940 210 : break;
941 686 : case L::neg_infinity:
942 686 : if(BOOST_JSON_UNLIKELY(
943 : ! h_.on_double(
944 : -std::numeric_limits<double>::infinity(),
945 : string_view(
946 : detail::literal_strings[ literal_index(L::neg_infinity) ],
947 : detail::literal_sizes[ literal_index(L::neg_infinity) ]),
948 : ec_)))
949 102 : return fail(cs.begin());
950 482 : break;
951 76 : case L::nan:
952 76 : if(BOOST_JSON_UNLIKELY(
953 : ! h_.on_double(
954 : std::numeric_limits<double>::quiet_NaN(),
955 : string_view(
956 : detail::literal_strings[ literal_index(L::nan) ],
957 : detail::literal_sizes[ literal_index(L::nan) ]),
958 : ec_)))
959 12 : return fail(cs.begin());
960 52 : break;
961 MIS 0 : default: BOOST_JSON_UNREACHABLE();
962 : }
963 :
964 HIT 1346 : cs += size;
965 1346 : return cs.begin();
966 : }
967 :
968 : //----------------------------------------------------------
969 :
970 : template<class Handler>
971 : template<bool StackEmpty_, bool IsKey_>
972 : const char*
973 161311 : basic_parser<Handler>::
974 : parse_string(const char* p,
975 : std::integral_constant<bool, StackEmpty_> stack_empty,
976 : std::integral_constant<bool, IsKey_> is_key,
977 : bool allow_bad_utf8,
978 : bool allow_bad_utf16)
979 : {
980 161311 : detail::const_stream_wrapper cs(p, end_);
981 : std::size_t total;
982 : char const* start;
983 : std::size_t size;
984 161311 : if(! stack_empty && ! st_.empty())
985 : {
986 : state st;
987 32906 : st_.pop(st);
988 32906 : st_.pop(total);
989 32906 : switch(st)
990 : {
991 MIS 0 : default: BOOST_JSON_UNREACHABLE();
992 HIT 3149 : case state::str2: goto do_str2;
993 1864 : case state::str8: goto do_str8;
994 27893 : case state::str1: break;
995 : }
996 : }
997 : else
998 : {
999 128405 : BOOST_ASSERT(*cs == '\x22'); // '"'
1000 128405 : ++cs;
1001 128405 : total = 0;
1002 : }
1003 :
1004 164791 : do_str1:
1005 164791 : start = cs.begin();
1006 329582 : cs = allow_bad_utf8?
1007 2177 : detail::count_valid<true>(cs.begin(), cs.end()):
1008 162614 : detail::count_valid<false>(cs.begin(), cs.end());
1009 164791 : size = cs.used(start);
1010 164791 : if(is_key)
1011 : {
1012 46694 : BOOST_ASSERT(total <= Handler::max_key_size);
1013 94005 : if(BOOST_JSON_UNLIKELY(size >
1014 : Handler::max_key_size - total))
1015 : {
1016 : BOOST_STATIC_CONSTEXPR source_location loc
1017 : = BOOST_CURRENT_LOCATION;
1018 3 : return fail(cs.begin(), error::key_too_large, &loc);
1019 : }
1020 : }
1021 : else
1022 : {
1023 35324 : BOOST_ASSERT(total <= Handler::max_string_size);
1024 70786 : if(BOOST_JSON_UNLIKELY(size >
1025 : Handler::max_string_size - total))
1026 : {
1027 : BOOST_STATIC_CONSTEXPR source_location loc
1028 : = BOOST_CURRENT_LOCATION;
1029 3 : return fail(cs.begin(), error::string_too_large, &loc);
1030 : }
1031 : }
1032 164785 : total += size;
1033 164785 : if(BOOST_JSON_UNLIKELY(! cs))
1034 : {
1035 : // call handler if the string isn't empty
1036 30227 : if(BOOST_JSON_LIKELY(size))
1037 : {
1038 : {
1039 27066 : bool r = is_key?
1040 12404 : h_.on_key_part( {start, size}, total, ec_ ):
1041 15996 : h_.on_string_part( {start, size}, total, ec_ );
1042 :
1043 25958 : if(BOOST_JSON_UNLIKELY(!r))
1044 : {
1045 1110 : return fail(cs.begin());
1046 : }
1047 : }
1048 : }
1049 28009 : return maybe_suspend(cs.begin(), state::str1, total);
1050 : }
1051 : // at this point all valid characters have been skipped, so any remaining
1052 : // if there are any more characters, they are either escaped, or incomplete
1053 : // utf8, or invalid utf8
1054 134558 : if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1055 : {
1056 : // sequence is invalid or incomplete
1057 15071 : if((*cs & 0x80) && !allow_bad_utf8)
1058 : {
1059 3465 : seq_.save(cs.begin(), cs.remain());
1060 3465 : if(BOOST_JSON_UNLIKELY(seq_.complete()))
1061 : {
1062 : BOOST_STATIC_CONSTEXPR source_location loc
1063 : = BOOST_CURRENT_LOCATION;
1064 1557 : return fail(cs.begin(), error::syntax, &loc);
1065 : }
1066 1908 : if(BOOST_JSON_LIKELY(size))
1067 : {
1068 245 : bool const r = is_key?
1069 22 : h_.on_key_part( {start, size}, total, ec_ ):
1070 245 : h_.on_string_part( {start, size}, total, ec_ );
1071 223 : if(BOOST_JSON_UNLIKELY( !r ))
1072 22 : return fail( cs.begin() );
1073 : }
1074 1864 : return maybe_suspend(cs.end(), state::str8, total);
1075 : }
1076 11606 : else if(BOOST_JSON_LIKELY(*cs == '\\'))
1077 : {
1078 : // flush unescaped run from input
1079 11497 : if(BOOST_JSON_LIKELY(size))
1080 : {
1081 4250 : bool const r = is_key?
1082 1226 : h_.on_key_part( {start, size}, total, ec_ ):
1083 3554 : h_.on_string_part( {start, size}, total, ec_ );
1084 3766 : if(BOOST_JSON_UNLIKELY( !r ))
1085 484 : return fail( cs.begin() );
1086 : }
1087 7247 : do_str2:
1088 13678 : cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
1089 12716 : if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
1090 5473 : return suspend_or_fail(state::str2, total);
1091 :
1092 7243 : goto do_str1;
1093 : }
1094 : // illegal control
1095 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1096 109 : return fail(cs.begin(), error::syntax, &loc);
1097 : }
1098 :
1099 : {
1100 119487 : bool r = is_key?
1101 84511 : h_.on_key( {start, size}, total, ec_ ):
1102 41985 : h_.on_string( {start, size}, total, ec_ );
1103 :
1104 115113 : if(BOOST_JSON_UNLIKELY(!r))
1105 : {
1106 4318 : return fail(cs.begin());
1107 : }
1108 : }
1109 :
1110 110795 : ++cs;
1111 110795 : return cs.begin();
1112 :
1113 1864 : do_str8:
1114 1864 : uint8_t needed = seq_.needed();
1115 1864 : if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
1116 MIS 0 : return maybe_suspend(cs.end(), state::str8, total);
1117 HIT 1864 : if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
1118 : {
1119 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1120 210 : return fail(cs.begin(), error::syntax, &loc);
1121 : }
1122 : {
1123 1654 : std::size_t const n = seq_.length();
1124 : bool r;
1125 1654 : if(is_key)
1126 : {
1127 2 : BOOST_ASSERT(total <= Handler::max_key_size);
1128 2 : if(BOOST_JSON_UNLIKELY(n >
1129 : Handler::max_key_size - total))
1130 : {
1131 : BOOST_STATIC_CONSTEXPR source_location loc
1132 : = BOOST_CURRENT_LOCATION;
1133 1 : return fail(cs.begin(), error::key_too_large, &loc);
1134 : }
1135 1 : total += n;
1136 1 : r = h_.on_key_part( {seq_.data(), n}, total, ec_ );
1137 : }
1138 : else
1139 : {
1140 1 : BOOST_ASSERT(total <= Handler::max_string_size);
1141 1652 : if(BOOST_JSON_UNLIKELY(n >
1142 : Handler::max_string_size - total))
1143 : {
1144 : BOOST_STATIC_CONSTEXPR source_location loc
1145 : = BOOST_CURRENT_LOCATION;
1146 1 : return fail(cs.begin(), error::string_too_large, &loc);
1147 : }
1148 1651 : total += n;
1149 1651 : r = h_.on_string_part( {seq_.data(), n}, total, ec_ );
1150 : }
1151 1451 : if(BOOST_JSON_UNLIKELY( !r ))
1152 201 : return fail( cs.begin() );
1153 : }
1154 1250 : cs += needed;
1155 1250 : goto do_str1;
1156 : }
1157 :
1158 : template<class Handler>
1159 : template<bool StackEmpty_>
1160 : const char*
1161 13678 : basic_parser<Handler>::
1162 : parse_escaped(
1163 : const char* p,
1164 : std::size_t& total,
1165 : std::integral_constant<bool, StackEmpty_> stack_empty,
1166 : bool is_key,
1167 : bool allow_bad_utf16)
1168 : {
1169 13678 : constexpr unsigned urc = 0xFFFD; // Unicode replacement character
1170 13678 : auto const ev_too_large = is_key?
1171 : error::key_too_large : error::string_too_large;
1172 13678 : auto const max_size = is_key?
1173 : Handler::max_key_size : Handler::max_string_size;
1174 : int digit;
1175 :
1176 : //---------------------------------------------------------------
1177 : //
1178 : // To handle escapes, a local temporary buffer accumulates
1179 : // the unescaped result. The algorithm attempts to fill the
1180 : // buffer to capacity before invoking the handler.
1181 : // In some cases the temporary buffer needs to be flushed
1182 : // before it is full:
1183 : // * When the closing double quote is seen
1184 : // * When there in no more input (and more is expected later)
1185 : // A goal of the algorithm is to call the handler as few times
1186 : // as possible. Thus, when the first escape is encountered,
1187 : // the algorithm attempts to fill the temporary buffer first.
1188 : //
1189 13678 : detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1190 :
1191 : // Unescaped JSON is never larger than its escaped version.
1192 : // To efficiently process only what will fit in the temporary buffer,
1193 : // the size of the input stream is temporarily "clipped" to the size
1194 : // of the temporary buffer.
1195 : // handle escaped character
1196 13678 : detail::clipped_const_stream cs(p, end_);
1197 13678 : cs.clip(temp.max_size());
1198 :
1199 13678 : if(! stack_empty && ! st_.empty())
1200 : {
1201 : state st;
1202 3149 : st_.pop(st);
1203 3149 : switch(st)
1204 : {
1205 MIS 0 : default: BOOST_JSON_UNREACHABLE();
1206 HIT 528 : case state::str3: goto do_str3;
1207 392 : case state::str4: goto do_str4;
1208 390 : case state::str5: goto do_str5;
1209 389 : case state::str6: goto do_str6;
1210 386 : case state::str7: goto do_str7;
1211 232 : case state::sur1: goto do_sur1;
1212 188 : case state::sur2: goto do_sur2;
1213 164 : case state::sur3: goto do_sur3;
1214 162 : case state::sur4: goto do_sur4;
1215 160 : case state::sur5: goto do_sur5;
1216 158 : case state::sur6: goto do_sur6;
1217 : }
1218 : }
1219 :
1220 3781 : while(true)
1221 : {
1222 14310 : BOOST_ASSERT( temp.capacity() );
1223 14310 : BOOST_ASSERT(*cs == '\\');
1224 14310 : ++cs;
1225 15169 : do_str3:
1226 15374 : if(BOOST_JSON_UNLIKELY(! cs))
1227 : {
1228 561 : if(BOOST_JSON_LIKELY(! temp.empty()))
1229 : {
1230 MIS 0 : BOOST_ASSERT(total <= max_size);
1231 HIT 100 : if(BOOST_JSON_UNLIKELY(
1232 : temp.size() > max_size - total))
1233 : {
1234 : BOOST_STATIC_CONSTEXPR source_location loc
1235 : = BOOST_CURRENT_LOCATION;
1236 MIS 0 : return fail(cs.begin(), ev_too_large, &loc);
1237 : }
1238 HIT 100 : total += temp.size();
1239 : {
1240 91 : bool r = is_key
1241 100 : ? h_.on_key_part(temp.get(), total, ec_)
1242 100 : : h_.on_string_part(temp.get(), total, ec_);
1243 :
1244 91 : if(BOOST_JSON_UNLIKELY(!r))
1245 : {
1246 9 : return fail(cs.begin());
1247 : }
1248 : }
1249 82 : temp.clear();
1250 : }
1251 543 : cs.clip(temp.max_size());
1252 543 : if(BOOST_JSON_UNLIKELY(! cs))
1253 543 : return maybe_suspend(cs.begin(), state::str3);
1254 : }
1255 14813 : switch(*cs)
1256 : {
1257 191 : default:
1258 : {
1259 : BOOST_STATIC_CONSTEXPR source_location loc
1260 : = BOOST_CURRENT_LOCATION;
1261 191 : return fail(cs.begin(), error::syntax, &loc);
1262 : }
1263 265 : case '\x22': // '"'
1264 265 : temp.push_back('\x22');
1265 265 : ++cs;
1266 265 : break;
1267 178 : case '\\':
1268 178 : temp.push_back('\\');
1269 178 : ++cs;
1270 178 : break;
1271 96 : case '/':
1272 96 : temp.push_back('/');
1273 96 : ++cs;
1274 96 : break;
1275 112 : case 'b':
1276 112 : temp.push_back('\x08');
1277 112 : ++cs;
1278 112 : break;
1279 108 : case 'f':
1280 108 : temp.push_back('\x0c');
1281 108 : ++cs;
1282 108 : break;
1283 1763 : case 'n':
1284 1763 : temp.push_back('\x0a');
1285 1763 : ++cs;
1286 1763 : break;
1287 146 : case 'r':
1288 146 : temp.push_back('\x0d');
1289 146 : ++cs;
1290 146 : break;
1291 266 : case 't':
1292 266 : temp.push_back('\x09');
1293 266 : ++cs;
1294 266 : break;
1295 11688 : case 'u':
1296 : // utf16 escape
1297 : //
1298 : // fast path only when the buffer
1299 : // is large enough for 2 surrogates
1300 11688 : if(BOOST_JSON_LIKELY(cs.remain() > 10))
1301 : {
1302 : // KRYSTIAN TODO: this could be done
1303 : // with fewer instructions
1304 11394 : digit = detail::load_little_endian<4>(
1305 5697 : cs.begin() + 1);
1306 5697 : int d4 = detail::hex_digit(static_cast<
1307 5697 : unsigned char>(digit >> 24));
1308 5697 : int d3 = detail::hex_digit(static_cast<
1309 5697 : unsigned char>(digit >> 16));
1310 5697 : int d2 = detail::hex_digit(static_cast<
1311 5697 : unsigned char>(digit >> 8));
1312 5697 : int d1 = detail::hex_digit(static_cast<
1313 : unsigned char>(digit));
1314 5697 : if(BOOST_JSON_UNLIKELY(
1315 : (d1 | d2 | d3 | d4) == -1))
1316 : {
1317 60 : if(d1 != -1)
1318 45 : ++cs;
1319 60 : if(d2 != -1)
1320 30 : ++cs;
1321 60 : if(d3 != -1)
1322 15 : ++cs;
1323 : BOOST_STATIC_CONSTEXPR source_location loc
1324 : = BOOST_CURRENT_LOCATION;
1325 60 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1326 : }
1327 : // 32 bit unicode scalar value
1328 5637 : unsigned u1 =
1329 5637 : (d1 << 12) + (d2 << 8) +
1330 5637 : (d3 << 4) + d4;
1331 : // valid unicode scalar values are
1332 : // [0, D7FF] and [E000, 10FFFF]
1333 : // values within this range are valid utf-8
1334 : // code points and invalid leading surrogates.
1335 5637 : if(BOOST_JSON_LIKELY(
1336 : u1 < 0xd800 || u1 > 0xdfff))
1337 : {
1338 1340 : cs += 5;
1339 1340 : temp.append_utf8(u1);
1340 1340 : break;
1341 : }
1342 4297 : if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1343 : {
1344 : // If it's an illegal leading surrogate and
1345 : // the parser does not allow it, return an error.
1346 707 : if(!allow_bad_utf16)
1347 : {
1348 : BOOST_STATIC_CONSTEXPR source_location loc
1349 : = BOOST_CURRENT_LOCATION;
1350 122 : return fail(cs.begin(), error::illegal_leading_surrogate,
1351 122 : &loc);
1352 : }
1353 : // Otherwise, append the Unicode replacement character
1354 : else
1355 : {
1356 585 : cs += 5;
1357 585 : temp.append_utf8(urc);
1358 585 : break;
1359 : }
1360 : }
1361 3590 : 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 3590 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1366 : {
1367 : // If the next character is not a backslash and
1368 : // the parser does not allow it, return a syntax error.
1369 156 : if(!allow_bad_utf16)
1370 : {
1371 : BOOST_STATIC_CONSTEXPR source_location loc
1372 : = BOOST_CURRENT_LOCATION;
1373 15 : return fail(cs.begin(), error::syntax, &loc);
1374 : }
1375 : // Otherwise, append the Unicode replacement character since
1376 : // the first code point is a valid leading surrogate
1377 : else
1378 : {
1379 141 : temp.append_utf8(urc);
1380 141 : break;
1381 : }
1382 : }
1383 3434 : ++cs;
1384 3434 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1385 : {
1386 220 : if (!allow_bad_utf16)
1387 : {
1388 : BOOST_STATIC_CONSTEXPR source_location loc
1389 : = BOOST_CURRENT_LOCATION;
1390 15 : return fail(cs.begin(), error::syntax, &loc);
1391 : }
1392 : // Otherwise, append the Unicode replacement character since
1393 : // the first code point is a valid leading surrogate
1394 : else
1395 : {
1396 205 : temp.append_utf8(urc);
1397 205 : goto do_str3;
1398 : }
1399 : }
1400 3214 : ++cs;
1401 3214 : digit = detail::load_little_endian<4>(cs.begin());
1402 3214 : d4 = detail::hex_digit(static_cast<
1403 3214 : unsigned char>(digit >> 24));
1404 3214 : d3 = detail::hex_digit(static_cast<
1405 3214 : unsigned char>(digit >> 16));
1406 3214 : d2 = detail::hex_digit(static_cast<
1407 3214 : unsigned char>(digit >> 8));
1408 3214 : d1 = detail::hex_digit(static_cast<
1409 : unsigned char>(digit));
1410 3214 : if(BOOST_JSON_UNLIKELY(
1411 : (d1 | d2 | d3 | d4) == -1))
1412 : {
1413 90 : if(d1 != -1)
1414 75 : ++cs;
1415 90 : if(d2 != -1)
1416 45 : ++cs;
1417 90 : if(d3 != -1)
1418 15 : ++cs;
1419 : BOOST_STATIC_CONSTEXPR source_location loc
1420 : = BOOST_CURRENT_LOCATION;
1421 90 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1422 : }
1423 3124 : unsigned u2 =
1424 3124 : (d1 << 12) + (d2 << 8) +
1425 3124 : (d3 << 4) + d4;
1426 : // Check if the second code point is a valid trailing surrogate.
1427 : // Valid trailing surrogates are [DC00, DFFF]
1428 3124 : if(BOOST_JSON_UNLIKELY(
1429 : u2 < 0xdc00 || u2 > 0xdfff))
1430 : {
1431 : // If not valid and the parser does not allow it, return an error.
1432 1353 : if(!allow_bad_utf16)
1433 : {
1434 : BOOST_STATIC_CONSTEXPR source_location loc
1435 : = BOOST_CURRENT_LOCATION;
1436 136 : return fail(cs.begin(), error::illegal_trailing_surrogate,
1437 136 : &loc);
1438 : }
1439 : // Append the replacement character for the
1440 : // first leading surrogate.
1441 1217 : cs += 4;
1442 1217 : temp.append_utf8(urc);
1443 : // Check if the second code point is a
1444 : // valid unicode scalar value (invalid leading
1445 : // or trailing surrogate)
1446 1217 : if (u2 < 0xd800 || u2 > 0xdbff)
1447 : {
1448 524 : temp.append_utf8(u2);
1449 524 : break;
1450 : }
1451 : // If it is a valid leading surrogate
1452 : else
1453 : {
1454 693 : u1_ = u2;
1455 693 : goto do_sur1;
1456 : }
1457 : }
1458 1771 : cs += 4;
1459 : // Calculate the Unicode code point from the surrogate pair and
1460 : // append the UTF-8 representation.
1461 1771 : unsigned cp =
1462 1771 : ((u1 - 0xd800) << 10) +
1463 : ((u2 - 0xdc00)) +
1464 : 0x10000;
1465 : // utf-16 surrogate pair
1466 1771 : temp.append_utf8(cp);
1467 1771 : break;
1468 : }
1469 : // flush
1470 5991 : if(BOOST_JSON_LIKELY(! temp.empty()))
1471 : {
1472 3 : BOOST_ASSERT(total <= max_size);
1473 1722 : if(BOOST_JSON_UNLIKELY(
1474 : temp.size() > max_size - total))
1475 : {
1476 : BOOST_STATIC_CONSTEXPR source_location loc
1477 : = BOOST_CURRENT_LOCATION;
1478 MIS 0 : return fail(cs.begin(), ev_too_large, &loc);
1479 : }
1480 HIT 1722 : total += temp.size();
1481 : {
1482 1582 : bool r = is_key
1483 1722 : ? h_.on_key_part(temp.get(), total, ec_)
1484 1722 : : h_.on_string_part(temp.get(), total, ec_);
1485 :
1486 1582 : if(BOOST_JSON_UNLIKELY(!r))
1487 : {
1488 140 : return fail(cs.begin());
1489 : }
1490 : }
1491 1442 : temp.clear();
1492 1442 : cs.clip(temp.max_size());
1493 : }
1494 5711 : ++cs;
1495 : // utf-16 escape
1496 6103 : do_str4:
1497 6103 : if(BOOST_JSON_UNLIKELY(! cs))
1498 392 : return maybe_suspend(cs.begin(), state::str4);
1499 5711 : digit = detail::hex_digit(*cs);
1500 5711 : if(BOOST_JSON_UNLIKELY(digit == -1))
1501 : {
1502 : BOOST_STATIC_CONSTEXPR source_location loc
1503 : = BOOST_CURRENT_LOCATION;
1504 50 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1505 : }
1506 5661 : ++cs;
1507 5661 : u1_ = digit << 12;
1508 6051 : do_str5:
1509 6051 : if(BOOST_JSON_UNLIKELY(! cs))
1510 390 : return maybe_suspend(cs.begin(), state::str5);
1511 5661 : digit = detail::hex_digit(*cs);
1512 5661 : if(BOOST_JSON_UNLIKELY(digit == -1))
1513 : {
1514 : BOOST_STATIC_CONSTEXPR source_location loc
1515 : = BOOST_CURRENT_LOCATION;
1516 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1517 : }
1518 5641 : ++cs;
1519 5641 : u1_ += digit << 8;
1520 6030 : do_str6:
1521 6030 : if(BOOST_JSON_UNLIKELY(! cs))
1522 389 : return maybe_suspend(cs.begin(), state::str6);
1523 5641 : digit = detail::hex_digit(*cs);
1524 5641 : if(BOOST_JSON_UNLIKELY(digit == -1))
1525 : {
1526 : BOOST_STATIC_CONSTEXPR source_location loc
1527 : = BOOST_CURRENT_LOCATION;
1528 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1529 : }
1530 5621 : ++cs;
1531 5621 : u1_ += digit << 4;
1532 6007 : do_str7:
1533 6007 : if(BOOST_JSON_UNLIKELY(! cs))
1534 386 : return maybe_suspend(cs.begin(), state::str7);
1535 5621 : digit = detail::hex_digit(*cs);
1536 5621 : if(BOOST_JSON_UNLIKELY(digit == -1))
1537 : {
1538 : BOOST_STATIC_CONSTEXPR source_location loc
1539 : = BOOST_CURRENT_LOCATION;
1540 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1541 : }
1542 5586 : ++cs;
1543 5586 : u1_ += digit;
1544 5586 : if(BOOST_JSON_LIKELY(
1545 : u1_ < 0xd800 || u1_ > 0xdfff))
1546 : {
1547 1434 : BOOST_ASSERT(temp.empty());
1548 : // utf-8 codepoint
1549 1434 : temp.append_utf8(u1_);
1550 1434 : break;
1551 : }
1552 4152 : if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1553 : {
1554 : // If it's an illegal leading surrogate and
1555 : // the parser does not allow it, return an error.
1556 1585 : if(!allow_bad_utf16)
1557 : {
1558 : BOOST_STATIC_CONSTEXPR source_location loc
1559 : = BOOST_CURRENT_LOCATION;
1560 209 : return fail(cs.begin(), error::illegal_leading_surrogate, &loc);
1561 : }
1562 : // Otherwise, append the Unicode replacement character
1563 : else
1564 : {
1565 1376 : BOOST_ASSERT(temp.empty());
1566 1376 : temp.append_utf8(urc);
1567 1376 : break;
1568 : }
1569 : }
1570 2567 : do_sur1:
1571 3792 : if(BOOST_JSON_UNLIKELY(! cs))
1572 232 : return maybe_suspend(cs.begin(), state::sur1);
1573 3560 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1574 : {
1575 : // If the next character is not a backslash and
1576 : // the parser does not allow it, return a syntax error.
1577 952 : if(!allow_bad_utf16)
1578 : {
1579 : BOOST_STATIC_CONSTEXPR source_location loc
1580 : = BOOST_CURRENT_LOCATION;
1581 149 : return fail(cs.begin(), error::syntax, &loc);
1582 : }
1583 : // Otherwise, append the Unicode replacement character since
1584 : // the first code point is a valid leading surrogate
1585 : else
1586 : {
1587 803 : temp.append_utf8(urc);
1588 803 : break;
1589 : }
1590 : }
1591 2608 : ++cs;
1592 2796 : do_sur2:
1593 2796 : if(BOOST_JSON_UNLIKELY(! cs))
1594 188 : return maybe_suspend(cs.begin(), state::sur2);
1595 2608 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1596 : {
1597 396 : if (!allow_bad_utf16)
1598 : {
1599 : BOOST_STATIC_CONSTEXPR source_location loc
1600 : = BOOST_CURRENT_LOCATION;
1601 65 : return fail(cs.begin(), error::syntax, &loc);
1602 : }
1603 : // Otherwise, append the Unicode replacement character since
1604 : // the first code point is a valid leading surrogate
1605 : else
1606 : {
1607 331 : temp.append_utf8(urc);
1608 331 : goto do_str3;
1609 : }
1610 : }
1611 2212 : ++cs;
1612 2376 : do_sur3:
1613 2376 : if(BOOST_JSON_UNLIKELY(! cs))
1614 164 : return maybe_suspend(cs.begin(), state::sur3);
1615 2212 : digit = detail::hex_digit(*cs);
1616 2212 : if(BOOST_JSON_UNLIKELY(digit == -1))
1617 : {
1618 : BOOST_STATIC_CONSTEXPR source_location loc
1619 : = BOOST_CURRENT_LOCATION;
1620 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1621 : }
1622 2177 : ++cs;
1623 2177 : u2_ = digit << 12;
1624 2339 : do_sur4:
1625 2339 : if(BOOST_JSON_UNLIKELY(! cs))
1626 162 : return maybe_suspend(cs.begin(), state::sur4);
1627 2177 : digit = detail::hex_digit(*cs);
1628 2177 : if(BOOST_JSON_UNLIKELY(digit == -1))
1629 : {
1630 : BOOST_STATIC_CONSTEXPR source_location loc
1631 : = BOOST_CURRENT_LOCATION;
1632 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1633 : }
1634 2142 : ++cs;
1635 2142 : u2_ += digit << 8;
1636 2302 : do_sur5:
1637 2302 : if(BOOST_JSON_UNLIKELY(! cs))
1638 160 : return maybe_suspend(cs.begin(), state::sur5);
1639 2142 : digit = detail::hex_digit(*cs);
1640 2142 : if(BOOST_JSON_UNLIKELY(digit == -1))
1641 : {
1642 : BOOST_STATIC_CONSTEXPR source_location loc
1643 : = BOOST_CURRENT_LOCATION;
1644 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1645 : }
1646 2122 : ++cs;
1647 2122 : u2_ += digit << 4;
1648 2280 : do_sur6:
1649 2280 : if(BOOST_JSON_UNLIKELY(! cs))
1650 158 : return maybe_suspend(cs.begin(), state::sur6);
1651 2122 : digit = detail::hex_digit(*cs);
1652 2122 : if(BOOST_JSON_UNLIKELY(digit == -1))
1653 : {
1654 : BOOST_STATIC_CONSTEXPR source_location loc
1655 : = BOOST_CURRENT_LOCATION;
1656 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1657 : }
1658 2102 : ++cs;
1659 2102 : u2_ += digit;
1660 : // Check if the second code point is a valid trailing surrogate.
1661 : // Valid trailing surrogates are [DC00, DFFF]
1662 2102 : if(BOOST_JSON_UNLIKELY(
1663 : u2_ < 0xdc00 || u2_ > 0xdfff))
1664 : {
1665 : // If not valid and the parser does not allow it, return an error.
1666 580 : if(!allow_bad_utf16)
1667 : {
1668 : BOOST_STATIC_CONSTEXPR source_location loc
1669 : = BOOST_CURRENT_LOCATION;
1670 60 : return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1671 : }
1672 : // Append the replacement character for the
1673 : // first leading surrogate.
1674 520 : temp.append_utf8(urc);
1675 : // Check if the second code point is a
1676 : // valid unicode scalar value (invalid leading
1677 : // or trailing surrogate)
1678 520 : if (u2_ < 0xd800 || u2_ > 0xdbff)
1679 : {
1680 220 : temp.append_utf8(u2_);
1681 220 : break;
1682 : }
1683 : // If it is a valid leading surrogate
1684 : else
1685 : {
1686 300 : u1_ = u2_;
1687 300 : goto do_sur1;
1688 : }
1689 : }
1690 : // Calculate the Unicode code point from the surrogate pair and
1691 : // append the UTF-8 representation.
1692 1522 : unsigned cp =
1693 1522 : ((u1_ - 0xd800) << 10) +
1694 1522 : ((u2_ - 0xdc00)) +
1695 : 0x10000;
1696 : // utf-16 surrogate pair
1697 1522 : temp.append_utf8(cp);
1698 : }
1699 :
1700 : // flush
1701 12650 : if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
1702 8869 : break;
1703 : }
1704 :
1705 8869 : if(BOOST_JSON_LIKELY( temp.size() ))
1706 : {
1707 433 : BOOST_ASSERT(total <= max_size);
1708 8869 : if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
1709 : {
1710 : BOOST_STATIC_CONSTEXPR source_location loc
1711 : = BOOST_CURRENT_LOCATION;
1712 MIS 0 : return fail(cs.begin(), ev_too_large, &loc);
1713 : }
1714 :
1715 HIT 8869 : total += temp.size();
1716 8056 : bool const r = is_key
1717 8869 : ? h_.on_key_part(temp.get(), total, ec_)
1718 8152 : : h_.on_string_part(temp.get(), total, ec_);
1719 8056 : if(BOOST_JSON_UNLIKELY( !r ))
1720 813 : return fail( cs.begin() );
1721 : }
1722 :
1723 7243 : return cs.begin();
1724 : }
1725 :
1726 : //----------------------------------------------------------
1727 :
1728 : template<class Handler>
1729 : template<
1730 : bool StackEmpty_,
1731 : bool AllowComments_/*,
1732 : bool AllowTrailing_,
1733 : bool AllowBadUTF8_*/>
1734 : const char*
1735 109189 : basic_parser<Handler>::
1736 : parse_object(const char* p,
1737 : std::integral_constant<bool, StackEmpty_> stack_empty,
1738 : std::integral_constant<bool, AllowComments_> allow_comments,
1739 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1740 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1741 : bool allow_bad_utf16)
1742 : {
1743 109189 : detail::const_stream_wrapper cs(p, end_);
1744 : std::size_t size;
1745 109189 : if(! stack_empty && ! st_.empty())
1746 : {
1747 : // resume
1748 : state st;
1749 35058 : st_.pop(st);
1750 35058 : st_.pop(size);
1751 35058 : switch(st)
1752 : {
1753 MIS 0 : default: BOOST_JSON_UNREACHABLE();
1754 HIT 1595 : case state::obj1: goto do_obj1;
1755 235 : case state::obj2: goto do_obj2;
1756 12647 : case state::obj3: goto do_obj3;
1757 1690 : case state::obj4: goto do_obj4;
1758 251 : case state::obj5: goto do_obj5;
1759 1591 : case state::obj6: goto do_obj6;
1760 15448 : case state::obj7: goto do_obj7;
1761 426 : case state::obj8: goto do_obj8;
1762 660 : case state::obj9: goto do_obj9;
1763 181 : case state::obj10: goto do_obj10;
1764 334 : case state::obj11: goto do_obj11;
1765 : }
1766 : }
1767 74131 : BOOST_ASSERT(*cs == '{');
1768 74131 : size = 0;
1769 74131 : if(BOOST_JSON_UNLIKELY(! depth_))
1770 : {
1771 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1772 3 : return fail(cs.begin(), error::too_deep, &loc);
1773 : }
1774 74128 : --depth_;
1775 74128 : if(BOOST_JSON_UNLIKELY(
1776 : ! h_.on_object_begin(ec_)))
1777 2040 : return fail(cs.begin());
1778 70050 : ++cs;
1779 : // object:
1780 : // '{' *ws '}'
1781 : // '{' *ws string *ws ':' *ws value *ws *[ ',' *ws string *ws ':' *ws value *ws ] '}'
1782 73616 : do_obj1:
1783 73616 : cs = detail::count_whitespace(cs.begin(), cs.end());
1784 73616 : if(BOOST_JSON_UNLIKELY(! cs))
1785 1629 : return maybe_suspend(cs.begin(), state::obj1, size);
1786 71987 : if(BOOST_JSON_LIKELY(*cs != '}'))
1787 : {
1788 69088 : if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
1789 : {
1790 2411 : if(allow_comments && *cs == '/')
1791 : {
1792 2139 : do_obj2:
1793 2374 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1794 2290 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1795 319 : return suspend_or_fail(state::obj2, size);
1796 1971 : goto do_obj1;
1797 : }
1798 : BOOST_STATIC_CONSTEXPR source_location loc
1799 : = BOOST_CURRENT_LOCATION;
1800 272 : return fail(cs.begin(), error::syntax, &loc);
1801 : }
1802 66677 : loop:
1803 80829 : if(BOOST_JSON_UNLIKELY(++size >
1804 : Handler::max_object_size))
1805 : {
1806 : BOOST_STATIC_CONSTEXPR source_location loc
1807 : = BOOST_CURRENT_LOCATION;
1808 1 : return fail(cs.begin(), error::object_too_large, &loc);
1809 : }
1810 80828 : do_obj3:
1811 93475 : cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
1812 90519 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1813 15592 : return suspend_or_fail(state::obj3, size);
1814 74927 : do_obj4:
1815 79088 : cs = detail::count_whitespace(cs.begin(), cs.end());
1816 79088 : if(BOOST_JSON_UNLIKELY(! cs))
1817 1705 : return maybe_suspend(cs.begin(), state::obj4, size);
1818 77383 : if(BOOST_JSON_UNLIKELY(*cs != ':'))
1819 : {
1820 2925 : if(allow_comments && *cs == '/')
1821 : {
1822 2779 : do_obj5:
1823 3030 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1824 2876 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1825 405 : return suspend_or_fail(state::obj5, size);
1826 2471 : goto do_obj4;
1827 : }
1828 : BOOST_STATIC_CONSTEXPR source_location loc
1829 : = BOOST_CURRENT_LOCATION;
1830 146 : return fail(cs.begin(), error::syntax, &loc);
1831 : }
1832 74458 : ++cs;
1833 76049 : do_obj6:
1834 76049 : cs = detail::count_whitespace(cs.begin(), cs.end());
1835 76049 : if(BOOST_JSON_UNLIKELY(! cs))
1836 1622 : return maybe_suspend(cs.begin(), state::obj6, size);
1837 74427 : do_obj7:
1838 89875 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1839 82526 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1840 23593 : return suspend_or_fail(state::obj7, size);
1841 58933 : do_obj8:
1842 61195 : cs = detail::count_whitespace(cs.begin(), cs.end());
1843 61195 : if(BOOST_JSON_UNLIKELY(! cs))
1844 441 : return maybe_suspend(cs.begin(), state::obj8, size);
1845 60754 : if(BOOST_JSON_LIKELY(*cs == ','))
1846 : {
1847 17792 : ++cs;
1848 19707 : do_obj9:
1849 19707 : cs = detail::count_whitespace(cs.begin(), cs.end());
1850 19707 : if(BOOST_JSON_UNLIKELY(! cs))
1851 690 : return maybe_suspend(cs.begin(), state::obj9, size);
1852 :
1853 : // loop for next element
1854 19017 : if(BOOST_JSON_LIKELY(*cs == '\x22'))
1855 14152 : goto loop;
1856 4865 : if(! allow_trailing || *cs != '}')
1857 : {
1858 1644 : if(allow_comments && *cs == '/')
1859 : {
1860 1433 : do_obj10:
1861 1614 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1862 1525 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1863 270 : return suspend_or_fail(state::obj10, size);
1864 1255 : goto do_obj9;
1865 : }
1866 : BOOST_STATIC_CONSTEXPR source_location loc
1867 : = BOOST_CURRENT_LOCATION;
1868 211 : return fail(cs.begin(), error::syntax, &loc);
1869 : }
1870 : }
1871 42962 : else if(BOOST_JSON_UNLIKELY(*cs != '}'))
1872 : {
1873 2325 : if(allow_comments && *cs == '/')
1874 : {
1875 2172 : do_obj11:
1876 2506 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1877 2338 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1878 502 : return suspend_or_fail(state::obj11, size);
1879 1836 : goto do_obj8;
1880 : }
1881 : BOOST_STATIC_CONSTEXPR source_location loc
1882 : = BOOST_CURRENT_LOCATION;
1883 153 : return fail(cs.begin(), error::syntax, &loc);
1884 : }
1885 : // got closing brace, fall through
1886 : }
1887 46757 : if(BOOST_JSON_UNLIKELY(
1888 : ! h_.on_object_end(size, ec_)))
1889 1502 : return fail(cs.begin());
1890 43714 : ++depth_;
1891 43714 : ++cs;
1892 43714 : return cs.begin();
1893 : }
1894 :
1895 : //----------------------------------------------------------
1896 :
1897 : template<class Handler>
1898 : template<
1899 : bool StackEmpty_,
1900 : bool AllowComments_/*,
1901 : bool AllowTrailing_,
1902 : bool AllowBadUTF8_*/>
1903 : const char*
1904 26348 : basic_parser<Handler>::
1905 : parse_array(const char* p,
1906 : std::integral_constant<bool, StackEmpty_> stack_empty,
1907 : std::integral_constant<bool, AllowComments_> allow_comments,
1908 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1909 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1910 : bool allow_bad_utf16)
1911 : {
1912 26348 : detail::const_stream_wrapper cs(p, end_);
1913 : std::size_t size;
1914 26348 : if(! stack_empty && ! st_.empty())
1915 : {
1916 : // resume
1917 : state st;
1918 5730 : st_.pop(st);
1919 5730 : st_.pop(size);
1920 5730 : switch(st)
1921 : {
1922 MIS 0 : default: BOOST_JSON_UNREACHABLE();
1923 HIT 1052 : case state::arr1: goto do_arr1;
1924 384 : case state::arr2: goto do_arr2;
1925 2938 : case state::arr3: goto do_arr3;
1926 391 : case state::arr4: goto do_arr4;
1927 671 : case state::arr5: goto do_arr5;
1928 294 : case state::arr6: goto do_arr6;
1929 : }
1930 : }
1931 20618 : BOOST_ASSERT(*cs == '[');
1932 20618 : size = 0;
1933 20618 : if(BOOST_JSON_UNLIKELY(! depth_))
1934 : {
1935 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1936 34 : return fail(cs.begin(), error::too_deep, &loc);
1937 : }
1938 20584 : --depth_;
1939 20584 : if(BOOST_JSON_UNLIKELY(
1940 : ! h_.on_array_begin(ec_)))
1941 812 : return fail(cs.begin());
1942 18966 : ++cs;
1943 : // array:
1944 : // '[' *ws ']'
1945 : // '[' *ws value *ws *[ ',' *ws value *ws ] ']'
1946 21551 : do_arr1:
1947 21551 : cs = detail::count_whitespace(cs.begin(), cs.end());
1948 21551 : if(BOOST_JSON_UNLIKELY(! cs))
1949 1073 : return maybe_suspend(cs.begin(), state::arr1, size);
1950 20478 : if(BOOST_JSON_LIKELY(*cs != ']'))
1951 : {
1952 18730 : loop:
1953 26193 : if(allow_comments && *cs == '/')
1954 : {
1955 1789 : do_arr2:
1956 2173 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1957 2045 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1958 512 : return suspend_or_fail(state::arr2, size);
1959 1533 : goto do_arr1;
1960 : }
1961 24404 : if(BOOST_JSON_UNLIKELY(++size >
1962 : Handler::max_array_size))
1963 : {
1964 : BOOST_STATIC_CONSTEXPR source_location loc
1965 : = BOOST_CURRENT_LOCATION;
1966 1 : return fail(cs.begin(), error::array_too_large, &loc);
1967 : }
1968 24403 : do_arr3:
1969 : // array is not empty, value required
1970 27341 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1971 24710 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1972 9052 : return suspend_or_fail(state::arr3, size);
1973 15658 : do_arr4:
1974 17279 : cs = detail::count_whitespace(cs.begin(), cs.end());
1975 17279 : if(BOOST_JSON_UNLIKELY(! cs))
1976 500 : return maybe_suspend(cs.begin(), state::arr4, size);
1977 16779 : if(BOOST_JSON_LIKELY(*cs == ','))
1978 : {
1979 9176 : ++cs;
1980 9847 : do_arr5:
1981 9847 : cs = detail::count_whitespace(cs.begin(), cs.end());
1982 9847 : if(BOOST_JSON_UNLIKELY(! cs))
1983 701 : return maybe_suspend(cs.begin(), state::arr5, size);
1984 : // loop for next element
1985 9146 : if(! allow_trailing || *cs != ']')
1986 7463 : goto loop;
1987 : }
1988 7603 : else if(BOOST_JSON_UNLIKELY(*cs != ']'))
1989 : {
1990 1969 : if(allow_comments && *cs == '/')
1991 : {
1992 1541 : do_arr6:
1993 1835 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1994 1688 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1995 458 : return suspend_or_fail(state::arr6, size);
1996 1230 : goto do_arr4;
1997 : }
1998 : BOOST_STATIC_CONSTEXPR source_location loc
1999 : = BOOST_CURRENT_LOCATION;
2000 428 : return fail(cs.begin(), error::syntax, &loc);
2001 : }
2002 : // got closing bracket; fall through
2003 : }
2004 9065 : if(BOOST_JSON_UNLIKELY(
2005 : ! h_.on_array_end(size, ec_)))
2006 547 : return fail(cs.begin());
2007 7939 : ++depth_;
2008 7939 : ++cs;
2009 7939 : return cs.begin();
2010 : }
2011 :
2012 : //----------------------------------------------------------
2013 :
2014 : template<class Handler>
2015 : template<bool StackEmpty_, char First_, number_precision Numbers_>
2016 : char const*
2017 2110611 : basic_parser<Handler>::parse_number(
2018 : char const* p,
2019 : std::integral_constant<bool, StackEmpty_> stack_empty,
2020 : std::integral_constant<char, First_> first,
2021 : std::integral_constant<number_precision, Numbers_> mode)
2022 : {
2023 : BOOST_CORE_STATIC_ASSERT(Numbers_ != number_precision::none);
2024 2110611 : constexpr bool precise_parsing = mode == number_precision::precise;
2025 :
2026 : // only one of these will be true if we are not resuming
2027 : // if negative then !zero_first && !nonzero_first
2028 : // if zero_first then !nonzero_first && !negative
2029 : // if nonzero_first then !zero_first && !negative
2030 2110611 : bool const negative = first == '-';
2031 2110611 : bool const zero_first = first == '0';
2032 2110611 : bool const nonzero_first = first == '+';
2033 2110611 : detail::const_stream_wrapper cs(p, end_);
2034 : number num;
2035 2110611 : const char* begin = cs.begin();
2036 2110611 : if(stack_empty || st_.empty())
2037 : {
2038 2080439 : num.bias = 0;
2039 2080439 : num.exp = 0;
2040 2080439 : num.frac = false;
2041 2080439 : num_buf_.clear();
2042 :
2043 : //----------------------------------
2044 : //
2045 : // '-'
2046 : // leading minus sign
2047 : //
2048 2080439 : BOOST_ASSERT(cs);
2049 : if(negative)
2050 21280 : ++cs;
2051 :
2052 2080439 : num.neg = negative;
2053 2080439 : num.frac = false;
2054 2080439 : num.exp = 0;
2055 2080439 : num.bias = 0;
2056 :
2057 : // fast path
2058 2080439 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
2059 : {
2060 : int n1;
2061 :
2062 7569 : if( nonzero_first ||
2063 7569 : (negative && *cs != '0') )
2064 : {
2065 2006470 : n1 = detail::count_digits( cs.begin() );
2066 2006470 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2067 :
2068 1450 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2069 : {
2070 9 : return parse_literal(
2071 : p - 1,
2072 8 : detail::literals_c<detail::literals::neg_infinity>());
2073 : }
2074 :
2075 1441 : if( ! nonzero_first && n1 == 0 )
2076 : {
2077 : // digit required
2078 : BOOST_STATIC_CONSTEXPR source_location loc
2079 : = BOOST_CURRENT_LOCATION;
2080 2 : return fail(cs.begin(), error::syntax, &loc);
2081 : }
2082 :
2083 2006459 : num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
2084 2006459 : cs += n1;
2085 :
2086 : // integer or floating-point with
2087 : // >= 16 leading digits
2088 2006459 : if( n1 == 16 )
2089 : {
2090 2001197 : goto do_num2;
2091 : }
2092 : }
2093 : else
2094 : {
2095 : // 0. floating-point or 0e integer
2096 15960 : num.mant = 0;
2097 15960 : n1 = 0;
2098 15960 : ++cs;
2099 : }
2100 :
2101 : {
2102 21222 : const char c = *cs;
2103 21222 : if(c != '.')
2104 : {
2105 8242 : if((c | 32) == 'e')
2106 : {
2107 4947 : ++cs;
2108 4947 : goto do_exp1;
2109 : }
2110 : BOOST_IF_CONSTEXPR( negative )
2111 20 : num.mant = ~num.mant + 1;
2112 3295 : goto finish_signed;
2113 : }
2114 : }
2115 :
2116 : // floating-point number
2117 :
2118 12980 : ++cs;
2119 :
2120 12980 : int n2 = detail::count_digits( cs.begin() );
2121 12980 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2122 :
2123 12980 : if( n2 == 0 )
2124 : {
2125 : // digit required
2126 : BOOST_STATIC_CONSTEXPR source_location loc
2127 : = BOOST_CURRENT_LOCATION;
2128 3 : return fail(cs.begin(), error::syntax, &loc);
2129 : }
2130 :
2131 : // floating-point mantissa overflow
2132 12977 : if( n1 + n2 >= 19 )
2133 : {
2134 122 : goto do_num7;
2135 : }
2136 :
2137 12855 : num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
2138 12855 : BOOST_ASSERT(num.bias == 0);
2139 12855 : num.bias -= n2;
2140 :
2141 12855 : cs += n2;
2142 :
2143 12855 : char ch = *cs;
2144 :
2145 12855 : if( (ch | 32) == 'e' )
2146 : {
2147 110 : ++cs;
2148 110 : goto do_exp1;
2149 : }
2150 12745 : else if( ch >= '0' && ch <= '9' )
2151 : {
2152 7517 : goto do_num8;
2153 : }
2154 :
2155 5228 : goto finish_dub;
2156 : }
2157 : }
2158 : else
2159 : {
2160 30172 : num = num_;
2161 : state st;
2162 30172 : st_.pop(st);
2163 30172 : switch(st)
2164 : {
2165 MIS 0 : default: BOOST_JSON_UNREACHABLE();
2166 HIT 538 : case state::num1: goto do_num1;
2167 6120 : case state::num2: goto do_num2;
2168 802 : case state::num3: goto do_num3;
2169 52 : case state::num4: goto do_num4;
2170 919 : case state::num5: goto do_num5;
2171 570 : case state::num6: goto do_num6;
2172 516 : case state::num7: goto do_num7;
2173 10944 : case state::num8: goto do_num8;
2174 423 : case state::exp1: goto do_exp1;
2175 129 : case state::exp2: goto do_exp2;
2176 9159 : case state::exp3: goto do_exp3;
2177 : }
2178 : }
2179 :
2180 : //----------------------------------
2181 : //
2182 : // DIGIT
2183 : // first digit
2184 : //
2185 58547 : do_num1:
2186 14249 : if(zero_first || nonzero_first ||
2187 14249 : BOOST_JSON_LIKELY(cs))
2188 : {
2189 57889 : char const c = *cs;
2190 : if(zero_first)
2191 : {
2192 8474 : ++cs;
2193 8474 : num.mant = 0;
2194 8474 : goto do_num6;
2195 : }
2196 13591 : else if(nonzero_first || BOOST_JSON_LIKELY(
2197 : c >= '1' && c <= '9'))
2198 : {
2199 41664 : ++cs;
2200 41664 : num.mant = c - '0';
2201 : }
2202 7751 : else if(BOOST_JSON_UNLIKELY(
2203 : c == '0'))
2204 : {
2205 6556 : ++cs;
2206 6556 : num.mant = 0;
2207 6556 : goto do_num6;
2208 : }
2209 1195 : else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
2210 : {
2211 1007 : st_.push(state::lit1);
2212 1007 : cur_lit_ = literal_index(detail::literals::neg_infinity);
2213 1007 : lit_offset_ = 1;
2214 1007 : return parse_literal(
2215 961 : cs.begin(), detail::literals_c<detail::literals::resume>() );
2216 : }
2217 : else
2218 : {
2219 : BOOST_STATIC_CONSTEXPR source_location loc
2220 : = BOOST_CURRENT_LOCATION;
2221 188 : return fail(cs.begin(), error::syntax, &loc);
2222 : }
2223 : }
2224 : else
2225 : {
2226 658 : if(BOOST_JSON_UNLIKELY(
2227 : ! h_.on_number_part(
2228 : {begin, cs.used(begin)}, ec_)))
2229 60 : return fail(cs.begin());
2230 :
2231 : BOOST_IF_CONSTEXPR( precise_parsing )
2232 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2233 HIT 538 : return maybe_suspend(
2234 538 : cs.begin(), state::num1, num);
2235 : }
2236 :
2237 : //----------------------------------
2238 : //
2239 : // 1*DIGIT
2240 : // significant digits left of decimal
2241 : //
2242 2048981 : do_num2:
2243 2043110 : if(negative || (!stack_empty && num.neg))
2244 : {
2245 22141 : for(;;)
2246 : {
2247 29527 : if(BOOST_JSON_UNLIKELY(! cs))
2248 : {
2249 1889 : if(BOOST_JSON_UNLIKELY(more_))
2250 : {
2251 1437 : if(BOOST_JSON_UNLIKELY(
2252 : ! h_.on_number_part(
2253 : {begin, cs.used(begin)}, ec_)))
2254 69 : return fail(cs.begin());
2255 :
2256 : BOOST_IF_CONSTEXPR( precise_parsing )
2257 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2258 HIT 1299 : return suspend(cs.begin(), state::num2, num);
2259 : }
2260 452 : goto finish_int;
2261 : }
2262 27638 : char const c = *cs;
2263 27638 : if(BOOST_JSON_LIKELY(
2264 : c >= '0' && c <= '9'))
2265 : {
2266 22964 : ++cs;
2267 : // 9223372036854775808 INT64_MIN
2268 22964 : if( num.mant > 922337203685477580 || (
2269 22249 : num.mant == 922337203685477580 && c > '8'))
2270 : break;
2271 22141 : num.mant = 10 * num.mant + ( c - '0' );
2272 22141 : continue;
2273 : }
2274 4674 : goto do_num6; // [.eE]
2275 : }
2276 : }
2277 : else
2278 : {
2279 6879439 : for(;;)
2280 : {
2281 8921034 : if(BOOST_JSON_UNLIKELY(! cs))
2282 : {
2283 6240 : if(BOOST_JSON_UNLIKELY(more_))
2284 : {
2285 5627 : if(BOOST_JSON_UNLIKELY(
2286 : ! h_.on_number_part(
2287 : {begin, cs.used(begin)}, ec_)))
2288 406 : return fail(cs.begin());
2289 :
2290 : BOOST_IF_CONSTEXPR( precise_parsing )
2291 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2292 HIT 4821 : return suspend(cs.begin(), state::num2, num);
2293 : }
2294 613 : goto finish_int;
2295 : }
2296 8914794 : char const c = *cs;
2297 8914794 : if(BOOST_JSON_LIKELY(
2298 : c >= '0' && c <= '9'))
2299 : {
2300 6883264 : ++cs;
2301 : // 18446744073709551615 UINT64_MAX
2302 6883264 : if( num.mant > 1844674407370955161 || (
2303 6879861 : num.mant == 1844674407370955161 && c > '5'))
2304 : break;
2305 6879439 : num.mant = 10 * num.mant + ( c - '0' );
2306 : }
2307 : else
2308 : {
2309 2031530 : goto do_num6; // [.eE]
2310 : }
2311 : }
2312 : }
2313 4648 : ++num.bias;
2314 :
2315 : //----------------------------------
2316 : //
2317 : // 1*DIGIT
2318 : // non-significant digits left of decimal
2319 : //
2320 5450 : do_num3:
2321 11558 : for(;;)
2322 : {
2323 17008 : if(BOOST_JSON_UNLIKELY(! cs))
2324 : {
2325 1527 : if(BOOST_JSON_UNLIKELY(more_))
2326 : {
2327 894 : if(BOOST_JSON_UNLIKELY(
2328 : ! h_.on_number_part(
2329 : {begin, cs.used(begin)}, ec_)))
2330 46 : return fail(cs.begin());
2331 :
2332 : BOOST_IF_CONSTEXPR( precise_parsing )
2333 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2334 HIT 802 : return suspend(cs.begin(), state::num3, num);
2335 : }
2336 633 : goto finish_dub;
2337 : }
2338 15481 : char const c = *cs;
2339 15481 : if(BOOST_JSON_UNLIKELY(
2340 : c >= '0' && c <= '9'))
2341 : {
2342 11558 : if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
2343 : {
2344 : BOOST_STATIC_CONSTEXPR source_location loc
2345 : = BOOST_CURRENT_LOCATION;
2346 MIS 0 : return fail(cs.begin(), error::exponent_overflow, &loc);
2347 : }
2348 HIT 11558 : ++cs;
2349 11558 : ++num.bias;
2350 : }
2351 3923 : else if(BOOST_JSON_LIKELY(
2352 : c == '.'))
2353 : {
2354 2028 : ++cs;
2355 2028 : break;
2356 : }
2357 1895 : else if((c | 32) == 'e')
2358 : {
2359 546 : ++cs;
2360 546 : goto do_exp1;
2361 : }
2362 : else
2363 : {
2364 1349 : goto finish_dub;
2365 : }
2366 : }
2367 :
2368 : //----------------------------------
2369 : //
2370 : // DIGIT
2371 : // first non-significant digit
2372 : // to the right of decimal
2373 : //
2374 2080 : do_num4:
2375 : {
2376 2080 : if(BOOST_JSON_UNLIKELY(! cs))
2377 : {
2378 64 : if(BOOST_JSON_UNLIKELY(
2379 : ! h_.on_number_part(
2380 : {begin, cs.used(begin)}, ec_)))
2381 6 : return fail(cs.begin());
2382 :
2383 : BOOST_IF_CONSTEXPR( precise_parsing )
2384 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2385 HIT 52 : return maybe_suspend(
2386 52 : cs.begin(), state::num4, num);
2387 : }
2388 2016 : char const c = *cs;
2389 2016 : if(BOOST_JSON_LIKELY(
2390 : //static_cast<unsigned char>(c - '0') < 10))
2391 : c >= '0' && c <= '9'))
2392 : {
2393 1949 : ++cs;
2394 : }
2395 : else
2396 : {
2397 : // digit required
2398 : BOOST_STATIC_CONSTEXPR source_location loc
2399 : = BOOST_CURRENT_LOCATION;
2400 67 : return fail(cs.begin(), error::syntax, &loc);
2401 : }
2402 : }
2403 :
2404 : //----------------------------------
2405 : //
2406 : // 1*DIGIT
2407 : // non-significant digits
2408 : // to the right of decimal
2409 : //
2410 2004759 : do_num5:
2411 36805410 : for(;;)
2412 : {
2413 38810169 : if(BOOST_JSON_UNLIKELY(! cs))
2414 : {
2415 1851 : if(BOOST_JSON_UNLIKELY(more_))
2416 : {
2417 959 : if(BOOST_JSON_UNLIKELY(
2418 : ! h_.on_number_part(
2419 : {begin, cs.used(begin)}, ec_)))
2420 20 : return fail(cs.begin());
2421 :
2422 : BOOST_IF_CONSTEXPR( precise_parsing )
2423 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2424 HIT 919 : return suspend(cs.begin(), state::num5, num);
2425 : }
2426 892 : goto finish_dub;
2427 : }
2428 38808318 : char const c = *cs;
2429 38808318 : if(BOOST_JSON_LIKELY(
2430 : c >= '0' && c <= '9'))
2431 : {
2432 36805410 : ++cs;
2433 : }
2434 2002908 : else if((c | 32) == 'e')
2435 : {
2436 2000590 : ++cs;
2437 2000590 : goto do_exp1;
2438 : }
2439 : else
2440 : {
2441 2318 : goto finish_dub;
2442 : }
2443 : }
2444 :
2445 : //----------------------------------
2446 : //
2447 : // [.eE]
2448 : //
2449 2051804 : do_num6:
2450 : {
2451 2051804 : if(BOOST_JSON_UNLIKELY(! cs))
2452 : {
2453 702 : if(BOOST_JSON_UNLIKELY(more_))
2454 : {
2455 655 : if(BOOST_JSON_UNLIKELY(
2456 : ! h_.on_number_part(
2457 : {begin, cs.used(begin)}, ec_)))
2458 42 : return fail(cs.begin());
2459 :
2460 : BOOST_IF_CONSTEXPR( precise_parsing )
2461 2 : num_buf_.append( begin, cs.used(begin) );
2462 571 : return suspend(cs.begin(), state::num6, num);
2463 : }
2464 47 : goto finish_int;
2465 : }
2466 2051102 : char const c = *cs;
2467 2051102 : if(BOOST_JSON_LIKELY(
2468 : c == '.'))
2469 : {
2470 2013504 : ++cs;
2471 : }
2472 37598 : else if((c | 32) == 'e')
2473 : {
2474 8323 : ++cs;
2475 8323 : goto do_exp1;
2476 : }
2477 : else
2478 : {
2479 29275 : goto finish_int;
2480 : }
2481 : }
2482 :
2483 : //----------------------------------
2484 : //
2485 : // DIGIT
2486 : // first significant digit
2487 : // to the right of decimal
2488 : //
2489 2014142 : do_num7:
2490 : {
2491 2014142 : if(BOOST_JSON_UNLIKELY(! cs))
2492 : {
2493 591 : if(BOOST_JSON_UNLIKELY(more_))
2494 : {
2495 587 : if(BOOST_JSON_UNLIKELY(
2496 : ! h_.on_number_part(
2497 : {begin, cs.used(begin)}, ec_)))
2498 35 : return fail(cs.begin());
2499 :
2500 : BOOST_IF_CONSTEXPR( precise_parsing )
2501 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2502 HIT 517 : return suspend(cs.begin(), state::num7, num);
2503 : }
2504 : // digit required
2505 : BOOST_STATIC_CONSTEXPR source_location loc
2506 : = BOOST_CURRENT_LOCATION;
2507 4 : return fail(cs.begin(), error::syntax, &loc);
2508 : }
2509 2013551 : char const c = *cs;
2510 2013551 : if(BOOST_JSON_UNLIKELY(
2511 : c < '0' || c > '9'))
2512 : {
2513 : // digit required
2514 : BOOST_STATIC_CONSTEXPR source_location loc
2515 : = BOOST_CURRENT_LOCATION;
2516 169 : return fail(cs.begin(), error::syntax, &loc);
2517 : }
2518 : }
2519 :
2520 : //----------------------------------
2521 : //
2522 : // 1*DIGIT
2523 : // significant digits
2524 : // to the right of decimal
2525 : //
2526 2031843 : do_num8:
2527 3277926 : for(;;)
2528 : {
2529 5309769 : if(BOOST_JSON_UNLIKELY(! cs))
2530 : {
2531 12816 : if(BOOST_JSON_UNLIKELY(more_))
2532 : {
2533 11080 : if(BOOST_JSON_UNLIKELY(
2534 : ! h_.on_number_part(
2535 : {begin, cs.used(begin)}, ec_)))
2536 67 : return fail(cs.begin());
2537 :
2538 : BOOST_IF_CONSTEXPR( precise_parsing )
2539 2 : num_buf_.append( begin, cs.used(begin) );
2540 10945 : return suspend(cs.begin(), state::num8, num);
2541 : }
2542 1736 : goto finish_dub;
2543 : }
2544 5296953 : char const c = *cs;
2545 5296953 : if(BOOST_JSON_LIKELY(
2546 : c >= '0' && c <= '9'))
2547 : {
2548 5279817 : ++cs;
2549 5279817 : if(BOOST_JSON_LIKELY( num.mant <= 9007199254740991 )) // 2^53-1
2550 : {
2551 3277926 : if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
2552 : {
2553 : BOOST_STATIC_CONSTEXPR source_location loc
2554 : = BOOST_CURRENT_LOCATION;
2555 MIS 0 : return fail(cs.begin(), error::exponent_overflow, &loc);
2556 : }
2557 HIT 3277926 : --num.bias;
2558 3277926 : num.mant = 10 * num.mant + ( c - '0' );
2559 : }
2560 : else
2561 : {
2562 2001891 : goto do_num5;
2563 : }
2564 : }
2565 17136 : else if((c | 32) == 'e')
2566 : {
2567 11133 : ++cs;
2568 11133 : goto do_exp1;
2569 : }
2570 : else
2571 : {
2572 6003 : goto finish_dub;
2573 : }
2574 : }
2575 :
2576 : //----------------------------------
2577 : //
2578 : // *[+-]
2579 : //
2580 2026072 : do_exp1:
2581 2026072 : if(BOOST_JSON_UNLIKELY(! cs))
2582 : {
2583 519 : if(BOOST_JSON_UNLIKELY(
2584 : ! h_.on_number_part(
2585 : {begin, cs.used(begin)}, ec_)))
2586 48 : return fail(cs.begin());
2587 :
2588 : BOOST_IF_CONSTEXPR( precise_parsing )
2589 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2590 HIT 423 : return maybe_suspend(
2591 423 : cs.begin(), state::exp1, num);
2592 : }
2593 2025553 : if(*cs == '+')
2594 : {
2595 2150 : ++cs;
2596 : }
2597 2023403 : else if(*cs == '-')
2598 : {
2599 1001775 : ++cs;
2600 1001775 : num.frac = true;
2601 : }
2602 :
2603 : //----------------------------------
2604 : //
2605 : // DIGIT
2606 : // first digit of the exponent
2607 : //
2608 1021628 : do_exp2:
2609 : {
2610 2025682 : if(BOOST_JSON_UNLIKELY(! cs))
2611 : {
2612 176 : if(BOOST_JSON_UNLIKELY(more_))
2613 : {
2614 167 : if(BOOST_JSON_UNLIKELY(
2615 : ! h_.on_number_part(
2616 : {begin, cs.used(begin)}, ec_)))
2617 19 : return fail(cs.begin());
2618 :
2619 : BOOST_IF_CONSTEXPR( precise_parsing )
2620 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2621 HIT 129 : return suspend(cs.begin(), state::exp2, num);
2622 : }
2623 : // digit required
2624 : BOOST_STATIC_CONSTEXPR source_location loc
2625 : = BOOST_CURRENT_LOCATION;
2626 9 : return fail(cs.begin(), error::syntax, &loc);
2627 : }
2628 2025506 : char const c = *cs;
2629 2025506 : if(BOOST_JSON_UNLIKELY(
2630 : c < '0' || c > '9'))
2631 : {
2632 : // digit required
2633 : BOOST_STATIC_CONSTEXPR source_location loc
2634 : = BOOST_CURRENT_LOCATION;
2635 508 : return fail(cs.begin(), error::syntax, &loc);
2636 : }
2637 2024998 : ++cs;
2638 2024998 : num.exp = c - '0';
2639 : }
2640 :
2641 : //----------------------------------
2642 : //
2643 : // 1*DIGIT
2644 : // subsequent digits in the exponent
2645 : //
2646 2034157 : do_exp3:
2647 4925458 : for(;;)
2648 : {
2649 6959615 : if(BOOST_JSON_UNLIKELY(! cs))
2650 : {
2651 2015856 : if(BOOST_JSON_UNLIKELY(more_))
2652 : {
2653 9313 : if(BOOST_JSON_UNLIKELY(
2654 : ! h_.on_number_part(
2655 : {begin, cs.used(begin)}, ec_)))
2656 77 : return fail(cs.begin());
2657 :
2658 : BOOST_IF_CONSTEXPR( precise_parsing )
2659 MIS 0 : num_buf_.append( begin, cs.used(begin) );
2660 HIT 9159 : return suspend(cs.begin(), state::exp3, num);
2661 : }
2662 : }
2663 : else
2664 : {
2665 4943759 : char const c = *cs;
2666 4943759 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2667 : {
2668 4925458 : if(BOOST_JSON_UNLIKELY(
2669 : // 2147483647 INT_MAX
2670 : num.exp > 214748364 ||
2671 : (num.exp == 214748364 && c > '7')
2672 : ))
2673 3855 : num.exp = INT_MAX;
2674 : else
2675 4921603 : num.exp = 10 * num.exp + ( c - '0' );
2676 :
2677 4925458 : ++cs;
2678 4925458 : continue;
2679 : }
2680 : }
2681 2024844 : BOOST_ASSERT(num.exp >= 0);
2682 2024844 : if ( num.frac )
2683 : {
2684 1001639 : if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
2685 : {
2686 : // if exponent overflowed, bias is a very large negative
2687 : // number, and mantissa isn't zero, then we cannot parse the
2688 : // number correctly
2689 91 : if(BOOST_JSON_UNLIKELY(
2690 : (num.exp == INT_MAX) &&
2691 : (num.bias < 0) &&
2692 : (num.exp + num.bias < 308) &&
2693 : num.mant ))
2694 : {
2695 : BOOST_STATIC_CONSTEXPR source_location loc
2696 : = BOOST_CURRENT_LOCATION;
2697 MIS 0 : return fail(cs.begin(), error::exponent_overflow, &loc);
2698 : }
2699 :
2700 HIT 91 : num.bias = 0;
2701 91 : num.exp = INT_MAX;
2702 : }
2703 : }
2704 1023205 : else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
2705 : {
2706 : // if exponent overflowed, bias is a very large positive number,
2707 : // and mantissa isn't zero, then we cannot parse the
2708 : // number correctly
2709 MIS 0 : if(BOOST_JSON_UNLIKELY(
2710 : (num.exp == INT_MAX) &&
2711 : (num.bias > 0) &&
2712 : (num.exp - num.bias < 308) &&
2713 : num.mant ))
2714 : {
2715 : BOOST_STATIC_CONSTEXPR source_location loc
2716 : = BOOST_CURRENT_LOCATION;
2717 0 : return fail(cs.begin(), error::exponent_overflow, &loc);
2718 : }
2719 :
2720 0 : num.bias = 0;
2721 0 : num.exp = INT_MAX;
2722 : }
2723 HIT 2024844 : goto finish_dub;
2724 : }
2725 :
2726 30387 : finish_int:
2727 28458 : if(negative || (!stack_empty && num.neg))
2728 : {
2729 2531 : if(BOOST_JSON_UNLIKELY(
2730 : ! h_.on_int64(static_cast<
2731 : int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
2732 310 : return fail(cs.begin());
2733 1913 : return cs.begin();
2734 : }
2735 27856 : if(num.mant <= INT64_MAX)
2736 : {
2737 27555 : finish_signed:
2738 30830 : if(BOOST_JSON_UNLIKELY(
2739 : ! h_.on_int64(static_cast<
2740 : int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
2741 2267 : return fail(cs.begin());
2742 26303 : return cs.begin();
2743 : }
2744 321 : if(BOOST_JSON_UNLIKELY(
2745 : ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
2746 35 : return fail(cs.begin());
2747 254 : return cs.begin();
2748 2043003 : finish_dub:
2749 : double d;
2750 2043003 : std::size_t const size = cs.used(begin);
2751 2043003 : BOOST_ASSERT( !num_buf_.size() || precise_parsing );
2752 : BOOST_IF_CONSTEXPR( precise_parsing )
2753 : {
2754 1000052 : char const* data = begin;
2755 1000052 : std::size_t full_size = size;
2756 : // if we previously suspended or if the current input ends with the
2757 : // number, we need to copy the current part of the number to the
2758 : // temporary buffer
2759 1000052 : if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
2760 : {
2761 1 : data = num_buf_.append( begin, size );
2762 1 : full_size = num_buf_.size();
2763 : }
2764 1000052 : auto const err = detail::charconv::from_chars(
2765 : data, data + full_size, d );
2766 1000052 : BOOST_ASSERT( err.ec != std::errc::invalid_argument );
2767 1000052 : BOOST_ASSERT( err.ptr == data + full_size );
2768 : (void)err;
2769 : }
2770 : else
2771 1042951 : d = detail::dec_to_float(
2772 : num.mant,
2773 540839 : num.bias + (num.frac ?
2774 502112 : -num.exp : num.exp),
2775 1042951 : num.neg);
2776 2043003 : if(BOOST_JSON_UNLIKELY(
2777 : ! h_.on_double(d, {begin, size}, ec_)))
2778 1903 : return fail(cs.begin());
2779 2039197 : return cs.begin();
2780 : }
2781 :
2782 : //----------------------------------------------------------
2783 :
2784 : template<class Handler>
2785 : template<bool StackEmpty_, char First_>
2786 : char const*
2787 16277 : basic_parser<Handler>::skip_number(
2788 : char const* p,
2789 : std::integral_constant<bool, StackEmpty_> stack_empty,
2790 : std::integral_constant<char, First_> first)
2791 : {
2792 : // only one of these will be true if we are not resuming
2793 : // if negative then !zero_first && !nonzero_first
2794 : // if zero_first then !nonzero_first && !negative
2795 : // if nonzero_first then !zero_first && !negative
2796 16277 : bool negative = first == '-';
2797 16277 : bool const zero_first = first == '0';
2798 16277 : bool const nonzero_first = first == '+';
2799 16277 : detail::const_stream_wrapper cs(p, end_);
2800 16277 : const char* begin = cs.begin();
2801 16277 : if(stack_empty || st_.empty())
2802 : {
2803 : //----------------------------------
2804 : //
2805 : // '-'
2806 : // leading minus sign
2807 : //
2808 9258 : BOOST_ASSERT(cs);
2809 9258 : if(negative)
2810 3898 : ++cs;
2811 :
2812 : // fast path
2813 9258 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
2814 : {
2815 : int n1;
2816 :
2817 5614 : if( nonzero_first || (negative && *cs != '0') )
2818 : {
2819 848 : n1 = detail::count_digits( cs.begin() );
2820 848 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2821 :
2822 848 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2823 MIS 0 : return parse_literal(
2824 : p - 1,
2825 0 : detail::literals_c<detail::literals::neg_infinity>());
2826 :
2827 HIT 387 : if( ! nonzero_first && n1 == 0 )
2828 : {
2829 : // digit required
2830 : BOOST_STATIC_CONSTEXPR source_location loc
2831 : = BOOST_CURRENT_LOCATION;
2832 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
2833 : }
2834 :
2835 HIT 848 : cs += n1;
2836 :
2837 : // integer or floating-point with
2838 : // >= 16 leading digits
2839 848 : if( n1 == 16 )
2840 227 : goto do_num2;
2841 : }
2842 : else
2843 : {
2844 : // 0. floating-point or 0e integer
2845 5227 : n1 = 0;
2846 5227 : ++cs;
2847 : }
2848 :
2849 : {
2850 5848 : const char c = *cs;
2851 5848 : if(c != '.')
2852 : {
2853 1629 : if((c | 32) == 'e')
2854 : {
2855 1629 : ++cs;
2856 1629 : goto do_exp1;
2857 : }
2858 MIS 0 : goto finish_signed;
2859 : }
2860 : }
2861 :
2862 : // floating-point number
2863 :
2864 HIT 4219 : ++cs;
2865 :
2866 4219 : int n2 = detail::count_digits( cs.begin() );
2867 4219 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2868 :
2869 4219 : if( n2 == 0 )
2870 : {
2871 : // digit required
2872 : BOOST_STATIC_CONSTEXPR source_location loc
2873 : = BOOST_CURRENT_LOCATION;
2874 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
2875 : }
2876 :
2877 : // floating-point mantissa overflow
2878 HIT 4219 : if( n1 + n2 >= 19 )
2879 MIS 0 : goto do_num7;
2880 :
2881 HIT 4219 : cs += n2;
2882 :
2883 4219 : char ch = *cs;
2884 4219 : if( (ch | 32) == 'e' )
2885 : {
2886 MIS 0 : ++cs;
2887 0 : goto do_exp1;
2888 : }
2889 HIT 4219 : else if( ch >= '0' && ch <= '9' )
2890 : {
2891 2500 : goto do_num8;
2892 : }
2893 :
2894 1719 : goto finish_dub;
2895 : }
2896 : }
2897 : else
2898 : {
2899 7019 : negative = num_.neg;
2900 : state st;
2901 7019 : st_.pop(st);
2902 7019 : switch(st)
2903 : {
2904 MIS 0 : default: BOOST_JSON_UNREACHABLE();
2905 HIT 64 : case state::num1: goto do_num1;
2906 218 : case state::num2: goto do_num2;
2907 MIS 0 : case state::num3: goto do_num3;
2908 0 : case state::num4: goto do_num4;
2909 HIT 3618 : case state::num5: goto do_num5;
2910 96 : case state::num6: goto do_num6;
2911 100 : case state::num7: goto do_num7;
2912 MIS 0 : case state::num8: goto do_num8;
2913 HIT 46 : case state::exp1: goto do_exp1;
2914 4 : case state::exp2: goto do_exp2;
2915 2873 : case state::exp3: goto do_exp3;
2916 : }
2917 : }
2918 :
2919 : //----------------------------------
2920 : //
2921 : // DIGIT
2922 : // first digit
2923 : //
2924 3247 : do_num1:
2925 1542 : if( zero_first || nonzero_first || BOOST_JSON_LIKELY(cs) )
2926 : {
2927 3183 : char const c = *cs;
2928 : if(zero_first)
2929 : {
2930 1244 : ++cs;
2931 1244 : goto do_num6;
2932 : }
2933 1478 : else if( nonzero_first || BOOST_JSON_LIKELY(c >= '1' && c <= '9') )
2934 : {
2935 868 : ++cs;
2936 : }
2937 1071 : else if(BOOST_JSON_UNLIKELY( c == '0' ))
2938 : {
2939 1071 : ++cs;
2940 1071 : goto do_num6;
2941 : }
2942 MIS 0 : else if( negative && opt_.allow_infinity_and_nan )
2943 : {
2944 0 : st_.push(state::lit1);
2945 0 : cur_lit_ = literal_index(detail::literals::neg_infinity);
2946 0 : lit_offset_ = 1;
2947 0 : return parse_literal(
2948 0 : cs.begin(), detail::literals_c<detail::literals::resume>() );
2949 : }
2950 : else
2951 : {
2952 : BOOST_STATIC_CONSTEXPR source_location loc
2953 : = BOOST_CURRENT_LOCATION;
2954 0 : return fail(cs.begin(), error::syntax, &loc);
2955 : }
2956 : }
2957 : else
2958 : {
2959 HIT 64 : if(BOOST_JSON_UNLIKELY(
2960 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
2961 MIS 0 : return fail(cs.begin());
2962 :
2963 : number num;
2964 HIT 64 : num.neg = negative;
2965 64 : return maybe_suspend(cs.begin(), state::num1, num);
2966 : }
2967 :
2968 : //----------------------------------
2969 : //
2970 : // 1*DIGIT
2971 : // significant digits left of decimal
2972 : //
2973 1313 : do_num2:
2974 1313 : if(negative || (!stack_empty && negative))
2975 : {
2976 259 : for(;;)
2977 : {
2978 698 : if(BOOST_JSON_UNLIKELY(! cs))
2979 : {
2980 32 : if(BOOST_JSON_UNLIKELY(more_))
2981 : {
2982 32 : if(BOOST_JSON_UNLIKELY(
2983 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
2984 MIS 0 : return fail(cs.begin());
2985 :
2986 : number num;
2987 HIT 32 : num.neg = negative;
2988 32 : return suspend(cs.begin(), state::num2, num);
2989 : }
2990 MIS 0 : goto finish_int;
2991 : }
2992 HIT 666 : char const c = *cs;
2993 666 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2994 : {
2995 259 : ++cs;
2996 259 : continue;
2997 : }
2998 407 : goto do_num6; // [.eE]
2999 : }
3000 : }
3001 : else
3002 : {
3003 5598 : for(;;)
3004 : {
3005 6472 : if(BOOST_JSON_UNLIKELY(! cs))
3006 : {
3007 186 : if(BOOST_JSON_UNLIKELY(more_))
3008 : {
3009 186 : if(BOOST_JSON_UNLIKELY(
3010 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3011 MIS 0 : return fail(cs.begin());
3012 :
3013 : number num;
3014 HIT 186 : num.neg = negative;
3015 186 : return suspend(cs.begin(), state::num2, num);
3016 : }
3017 MIS 0 : goto finish_int;
3018 : }
3019 HIT 6286 : char const c = *cs;
3020 6286 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3021 5598 : ++cs;
3022 : else
3023 688 : goto do_num6; // [.eE]
3024 : }
3025 : }
3026 :
3027 : //----------------------------------
3028 : //
3029 : // 1*DIGIT
3030 : // non-significant digits left of decimal
3031 : //
3032 MIS 0 : do_num3:
3033 0 : for(;;)
3034 : {
3035 0 : if(BOOST_JSON_UNLIKELY(! cs))
3036 : {
3037 0 : if(BOOST_JSON_UNLIKELY(more_))
3038 : {
3039 0 : if(BOOST_JSON_UNLIKELY(
3040 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3041 0 : return fail(cs.begin());
3042 :
3043 : number num;
3044 0 : num.neg = negative;
3045 0 : return suspend(cs.begin(), state::num3, num);
3046 : }
3047 0 : goto finish_dub;
3048 : }
3049 0 : char const c = *cs;
3050 0 : if(BOOST_JSON_UNLIKELY( c >= '0' && c <= '9' ))
3051 : {
3052 0 : ++cs;
3053 : }
3054 0 : else if(BOOST_JSON_LIKELY( c == '.' ))
3055 : {
3056 0 : ++cs;
3057 0 : break;
3058 : }
3059 0 : else if( (c | 32) == 'e' )
3060 : {
3061 0 : ++cs;
3062 0 : goto do_exp1;
3063 : }
3064 : else
3065 : {
3066 0 : goto finish_dub;
3067 : }
3068 : }
3069 :
3070 : //----------------------------------
3071 : //
3072 : // DIGIT
3073 : // first non-significant digit
3074 : // to the right of decimal
3075 : //
3076 0 : do_num4:
3077 : {
3078 0 : if(BOOST_JSON_UNLIKELY(! cs))
3079 : {
3080 0 : if(BOOST_JSON_UNLIKELY(
3081 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3082 0 : return fail(cs.begin());
3083 :
3084 : number num;
3085 0 : num.neg = negative;
3086 0 : return maybe_suspend(cs.begin(), state::num4, num);
3087 : }
3088 0 : char const c = *cs;
3089 0 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3090 : {
3091 0 : ++cs;
3092 : }
3093 : else
3094 : {
3095 : // digit required
3096 : BOOST_STATIC_CONSTEXPR source_location loc
3097 : = BOOST_CURRENT_LOCATION;
3098 0 : return fail(cs.begin(), error::syntax, &loc);
3099 : }
3100 : }
3101 :
3102 : //----------------------------------
3103 : //
3104 : // 1*DIGIT
3105 : // non-significant digits
3106 : // to the right of decimal
3107 : //
3108 HIT 8711 : do_num5:
3109 1084422 : for(;;)
3110 : {
3111 1093133 : if(BOOST_JSON_UNLIKELY(! cs))
3112 : {
3113 4261 : if(BOOST_JSON_UNLIKELY(more_))
3114 : {
3115 3618 : if(BOOST_JSON_UNLIKELY(
3116 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3117 MIS 0 : return fail(cs.begin());
3118 :
3119 : number num;
3120 HIT 3618 : num.neg = negative;
3121 3618 : return suspend(cs.begin(), state::num5, num);
3122 : }
3123 643 : goto finish_dub;
3124 : }
3125 1088872 : char const c = *cs;
3126 1088872 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3127 : {
3128 1084422 : ++cs;
3129 : }
3130 4450 : else if( (c | 32) == 'e' )
3131 : {
3132 2646 : ++cs;
3133 2646 : goto do_exp1;
3134 : }
3135 : else
3136 : {
3137 1804 : goto finish_dub;
3138 : }
3139 : }
3140 :
3141 : //----------------------------------
3142 : //
3143 : // [.eE]
3144 : //
3145 3506 : do_num6:
3146 : {
3147 3506 : if(BOOST_JSON_UNLIKELY(! cs))
3148 : {
3149 96 : if(BOOST_JSON_UNLIKELY(more_))
3150 : {
3151 96 : if(BOOST_JSON_UNLIKELY(
3152 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3153 MIS 0 : return fail(cs.begin());
3154 :
3155 : number num;
3156 HIT 96 : num.neg = negative;
3157 96 : return suspend(cs.begin(), state::num6, num);
3158 : }
3159 MIS 0 : goto finish_int;
3160 : }
3161 HIT 3410 : char const c = *cs;
3162 3410 : if(BOOST_JSON_LIKELY(
3163 : c == '.'))
3164 : {
3165 2593 : ++cs;
3166 : }
3167 817 : else if( (c | 32) == 'e' )
3168 : {
3169 817 : ++cs;
3170 817 : goto do_exp1;
3171 : }
3172 : else
3173 : {
3174 MIS 0 : goto finish_int;
3175 : }
3176 : }
3177 :
3178 : //----------------------------------
3179 : //
3180 : // DIGIT
3181 : // first significant digit
3182 : // to the right of decimal
3183 : //
3184 HIT 2693 : do_num7:
3185 : {
3186 2693 : if(BOOST_JSON_UNLIKELY(! cs))
3187 : {
3188 100 : if(BOOST_JSON_UNLIKELY(more_))
3189 : {
3190 100 : if(BOOST_JSON_UNLIKELY(
3191 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3192 MIS 0 : return fail(cs.begin());
3193 :
3194 : number num;
3195 HIT 100 : num.neg = negative;
3196 100 : return suspend(cs.begin(), state::num7, num);
3197 : }
3198 : // digit required
3199 : BOOST_STATIC_CONSTEXPR source_location loc
3200 : = BOOST_CURRENT_LOCATION;
3201 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
3202 : }
3203 HIT 2593 : char const c = *cs;
3204 2593 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3205 : {
3206 : // digit required
3207 : BOOST_STATIC_CONSTEXPR source_location loc
3208 : = BOOST_CURRENT_LOCATION;
3209 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
3210 : }
3211 : }
3212 :
3213 : //----------------------------------
3214 : //
3215 : // 1*DIGIT
3216 : // significant digits
3217 : // to the right of decimal
3218 : //
3219 HIT 2593 : do_num8:
3220 : for(;;)
3221 : {
3222 5093 : if(BOOST_JSON_UNLIKELY(! cs))
3223 : {
3224 MIS 0 : if(BOOST_JSON_UNLIKELY(more_))
3225 : {
3226 0 : if(BOOST_JSON_UNLIKELY(
3227 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3228 0 : return fail(cs.begin());
3229 :
3230 : number num;
3231 0 : num.neg = negative;
3232 0 : return suspend(cs.begin(), state::num8, num);
3233 : }
3234 0 : goto finish_dub;
3235 : }
3236 HIT 5093 : char const c = *cs;
3237 5093 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3238 : {
3239 5093 : ++cs;
3240 5093 : goto do_num5;
3241 : }
3242 MIS 0 : else if( (c | 32) == 'e' )
3243 : {
3244 0 : ++cs;
3245 0 : goto do_exp1;
3246 : }
3247 : else
3248 : {
3249 0 : goto finish_dub;
3250 : }
3251 : }
3252 :
3253 : //----------------------------------
3254 : //
3255 : // *[+-]
3256 : //
3257 HIT 5138 : do_exp1:
3258 5138 : if(BOOST_JSON_UNLIKELY(! cs))
3259 : {
3260 46 : if(BOOST_JSON_UNLIKELY(
3261 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3262 MIS 0 : return fail(cs.begin());
3263 :
3264 : number num;
3265 HIT 46 : num.neg = negative;
3266 46 : return maybe_suspend(cs.begin(), state::exp1, num);
3267 : }
3268 5092 : if(*cs == '+')
3269 : {
3270 MIS 0 : ++cs;
3271 : }
3272 HIT 5092 : else if(*cs == '-')
3273 : {
3274 160 : ++cs;
3275 : }
3276 :
3277 : //----------------------------------
3278 : //
3279 : // DIGIT
3280 : // first digit of the exponent
3281 : //
3282 4932 : do_exp2:
3283 : {
3284 5096 : if(BOOST_JSON_UNLIKELY(! cs))
3285 : {
3286 4 : if(BOOST_JSON_UNLIKELY(more_))
3287 : {
3288 4 : if(BOOST_JSON_UNLIKELY(
3289 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3290 MIS 0 : return fail(cs.begin());
3291 :
3292 : number num;
3293 HIT 4 : num.neg = negative;
3294 4 : return suspend(cs.begin(), state::exp2, num);
3295 : }
3296 : // digit required
3297 : BOOST_STATIC_CONSTEXPR source_location loc
3298 : = BOOST_CURRENT_LOCATION;
3299 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
3300 : }
3301 HIT 5092 : char const c = *cs;
3302 5092 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3303 : {
3304 : // digit required
3305 : BOOST_STATIC_CONSTEXPR source_location loc
3306 : = BOOST_CURRENT_LOCATION;
3307 MIS 0 : return fail(cs.begin(), error::syntax, &loc);
3308 : }
3309 HIT 5092 : ++cs;
3310 : }
3311 :
3312 : //----------------------------------
3313 : //
3314 : // 1*DIGIT
3315 : // subsequent digits in the exponent
3316 : //
3317 7965 : do_exp3:
3318 540852 : for(;;)
3319 : {
3320 548817 : if(BOOST_JSON_UNLIKELY(! cs))
3321 : {
3322 4683 : if(BOOST_JSON_UNLIKELY(more_))
3323 : {
3324 2873 : if(BOOST_JSON_UNLIKELY(
3325 : ! h_.on_number_part( {begin, cs.used(begin)}, ec_ )))
3326 MIS 0 : return fail(cs.begin());
3327 :
3328 : number num;
3329 HIT 2873 : num.neg = negative;
3330 2873 : return suspend(cs.begin(), state::exp3, num);
3331 : }
3332 : }
3333 : else
3334 : {
3335 544134 : char const c = *cs;
3336 544134 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3337 : {
3338 540852 : ++cs;
3339 540852 : continue;
3340 : }
3341 : }
3342 5092 : goto finish_dub;
3343 : }
3344 :
3345 MIS 0 : finish_int:
3346 0 : if(negative)
3347 : {
3348 0 : if(BOOST_JSON_UNLIKELY(
3349 : ! h_.on_int64(0, {begin, cs.used(begin)}, ec_)))
3350 0 : return fail(cs.begin());
3351 0 : return cs.begin();
3352 : }
3353 0 : finish_signed:
3354 0 : if(BOOST_JSON_UNLIKELY(
3355 : ! h_.on_uint64(0, {begin, cs.used(begin)}, ec_)))
3356 0 : return fail(cs.begin());
3357 0 : return cs.begin();
3358 HIT 9258 : finish_dub:
3359 9258 : if(BOOST_JSON_UNLIKELY( !h_.on_double(0, {begin, cs.used(begin)}, ec_) ))
3360 MIS 0 : return fail(cs.begin());
3361 HIT 9258 : return cs.begin();
3362 : }
3363 :
3364 : //----------------------------------------------------------
3365 :
3366 : template<class Handler>
3367 : template<class... Args>
3368 2164608 : basic_parser<Handler>::
3369 : basic_parser(
3370 : parse_options const& opt,
3371 : Args&&... args)
3372 2164600 : : h_(std::forward<Args>(args)...)
3373 2164608 : , opt_(opt)
3374 : {
3375 2164608 : }
3376 :
3377 : //----------------------------------------------------------
3378 :
3379 : template<class Handler>
3380 : void
3381 4153132 : basic_parser<Handler>::
3382 : reset() noexcept
3383 : {
3384 4153132 : ec_ = {};
3385 4153132 : st_.clear();
3386 4153132 : more_ = true;
3387 4153132 : done_ = false;
3388 4153132 : clean_ = true;
3389 4153132 : num_buf_.clear();
3390 4153132 : }
3391 :
3392 : template<class Handler>
3393 : void
3394 16 : basic_parser<Handler>::
3395 : fail(system::error_code ec) noexcept
3396 : {
3397 16 : if(! ec)
3398 : {
3399 : // assign an arbitrary
3400 : // error code to prevent UB
3401 MIS 0 : BOOST_JSON_FAIL(ec_, error::incomplete);
3402 : }
3403 : else
3404 : {
3405 HIT 16 : ec_ = ec;
3406 : }
3407 16 : done_ = false;
3408 16 : }
3409 :
3410 : //----------------------------------------------------------
3411 :
3412 : template<class Handler>
3413 : std::size_t
3414 2334223 : basic_parser<Handler>::
3415 : write_some(
3416 : bool more,
3417 : char const* data,
3418 : std::size_t size,
3419 : system::error_code& ec)
3420 : {
3421 : // see if we exited via exception
3422 : // on the last call to write_some
3423 2334223 : if(! clean_)
3424 : {
3425 : // prevent UB
3426 1 : if(! ec_)
3427 : {
3428 1 : BOOST_JSON_FAIL(ec_, error::exception);
3429 : }
3430 : }
3431 2334223 : if(ec_)
3432 : {
3433 : // error is sticky
3434 5 : ec = ec_;
3435 5 : return 0;
3436 : }
3437 2334218 : clean_ = false;
3438 2334218 : more_ = more;
3439 2334218 : end_ = data + size;
3440 : const char* p;
3441 2334218 : if(BOOST_JSON_LIKELY(st_.empty()))
3442 : {
3443 : // first time
3444 2164594 : depth_ = opt_.max_depth;
3445 2164594 : if(BOOST_JSON_UNLIKELY(
3446 : ! h_.on_document_begin(ec_)))
3447 : {
3448 7889 : ec = ec_;
3449 7889 : return 0;
3450 : }
3451 2148815 : p = parse_document(data, std::true_type());
3452 : }
3453 : else
3454 : {
3455 169624 : p = parse_document(data, std::false_type());
3456 : }
3457 :
3458 2299340 : if(BOOST_JSON_LIKELY(p != sentinel()))
3459 : {
3460 2099052 : BOOST_ASSERT(! ec_);
3461 2099052 : if(! done_)
3462 : {
3463 2031637 : done_ = true;
3464 2031637 : h_.on_document_end(ec_);
3465 : }
3466 : }
3467 : else
3468 : {
3469 200288 : if(! ec_)
3470 : {
3471 173509 : if(! more_)
3472 : {
3473 573 : BOOST_JSON_FAIL(ec_, error::incomplete);
3474 : }
3475 172936 : else if(! st_.empty())
3476 : {
3477 : // consume as much trailing whitespace in
3478 : // the JSON document as possible, but still
3479 : // consider the parse complete
3480 : state st;
3481 172936 : st_.peek(st);
3482 172936 : if( st == state::doc3 &&
3483 88551 : ! done_)
3484 : {
3485 70724 : done_ = true;
3486 70724 : h_.on_document_end(ec_);
3487 : }
3488 : }
3489 : }
3490 198644 : p = end_;
3491 : }
3492 2293736 : ec = ec_;
3493 2293736 : clean_ = true;
3494 2293736 : return p - data;
3495 : }
3496 :
3497 : template<class Handler>
3498 : std::size_t
3499 1 : basic_parser<Handler>::
3500 : write_some(
3501 : bool more,
3502 : char const* data,
3503 : std::size_t size,
3504 : std::error_code& ec)
3505 : {
3506 1 : system::error_code jec;
3507 1 : std::size_t const result = write_some(more, data, size, jec);
3508 1 : ec = jec;
3509 1 : return result;
3510 : }
3511 :
3512 : #endif
3513 :
3514 : } // namespace json
3515 : } // namespace boost
3516 :
3517 : #ifdef _MSC_VER
3518 : #pragma warning(pop)
3519 : #endif
3520 :
3521 : #endif
|