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 1027645 : 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 1027645 : if( exp > 308 )
129 : {
130 455 : return std::numeric_limits<double>::infinity();
131 : }
132 1027190 : 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 1027039 : exp += 308;
141 1027039 : BOOST_ASSERT(exp >= 0 && exp < 618);
142 1027039 : return tab[exp];
143 : }
144 : }
145 :
146 : inline
147 : double
148 1033899 : 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 1033899 : double x = static_cast<double>(m);
155 1033899 : if(neg)
156 13171 : x = -x;
157 :
158 : // pow10 returns infinity for large exponents,
159 : // and zero times infinity is NaN
160 1033899 : if(m == 0)
161 6254 : return x;
162 :
163 1027645 : if(e < -305)
164 : {
165 5187 : x *= 1e-305 ;
166 5187 : e += 305;
167 : }
168 :
169 1027645 : if(e >= -22 && e < 0)
170 53321 : return x / pow10(-e);
171 :
172 974324 : return x * pow10(e);
173 : }
174 :
175 : inline
176 : bool
177 : is_control(char c) noexcept
178 : {
179 : return static_cast<unsigned char>(c) < 32;
180 : }
181 :
182 : inline
183 : int
184 66931 : hex_digit(unsigned char c) noexcept
185 : {
186 : // by Peter Dimov
187 66931 : if( c >= '0' && c <= '9' )
188 35759 : return c - '0';
189 31172 : c &= ~0x20;
190 31172 : if( c >= 'A' && c <= 'F' )
191 30562 : return 10 + c - 'A';
192 610 : return -1;
193 : }
194 :
195 : } // detail
196 :
197 : //----------------------------------------------------------
198 :
199 : template< class Handler >
200 : template< bool StackEmpty_, char First_ >
201 : struct basic_parser<Handler>::
202 : parse_number_helper
203 : {
204 : template<number_precision N>
205 : using index_t = mp11::mp_size_t<static_cast<std::size_t>(N)>;
206 :
207 : basic_parser* parser;
208 : char const* p;
209 :
210 : char const*
211 9483477 : operator()( index_t<number_precision::imprecise> ) const
212 : {
213 18961450 : return parser->parse_number(
214 9483477 : p,
215 : std::integral_constant<bool, StackEmpty_>(),
216 9477974 : std::integral_constant<char, First_>() );
217 : }
218 :
219 : char const*
220 1040553 : operator()( index_t<number_precision::precise> ) const
221 : {
222 2077655 : return parser->parse_number_precise(
223 1040553 : p,
224 : std::integral_constant<bool, StackEmpty_>(),
225 1037102 : std::integral_constant<char, First_>() );
226 : }
227 :
228 : char const*
229 40497 : operator()( index_t<number_precision::none> ) const
230 : {
231 77544 : return parser->skip_number(
232 40497 : p,
233 : std::integral_constant<bool, StackEmpty_>(),
234 37047 : std::integral_constant<char, First_>() );
235 : }
236 : };
237 :
238 : //----------------------------------------------------------
239 :
240 : template<class Handler>
241 : void
242 8627574 : basic_parser<Handler>::
243 : reserve()
244 : {
245 8627574 : if(BOOST_JSON_LIKELY(
246 : ! st_.empty()))
247 37573 : return;
248 : // Reserve the largest stack we need,
249 : // to avoid reallocation during suspend.
250 17180002 : st_.reserve(
251 : sizeof(state) + // document parsing state
252 : (sizeof(state) +
253 8590001 : sizeof(std::size_t)) * depth() + // array and object state + size
254 : sizeof(state) + // value parsing state
255 : sizeof(std::size_t) + // string size
256 : sizeof(state)); // comment state
257 : }
258 :
259 : //----------------------------------------------------------
260 : //
261 : // The sentinel value is returned by parse functions
262 : // to indicate that the parser failed, or suspended.
263 : // this is used as it is distinct from all valid values
264 : // for data in write
265 :
266 : template<class Handler>
267 : const char*
268 47489407 : basic_parser<Handler>::
269 : sentinel()
270 : {
271 : // the "+1" ensures that the returned pointer is unique even if
272 : // the given input buffer borders on this object
273 : return reinterpret_cast<
274 47489407 : const char*>(this) + 1;
275 : }
276 :
277 : template<class Handler>
278 : bool
279 10897335 : basic_parser<Handler>::
280 : incomplete(
281 : const detail::const_stream_wrapper& cs)
282 : {
283 10897335 : return cs.begin() == sentinel();
284 : }
285 :
286 : //----------------------------------------------------------
287 : //
288 : // These functions are declared with the BOOST_NOINLINE
289 : // attribute to avoid polluting the parsers hot-path.
290 : // They return the canary value to indicate suspension
291 : // or failure.
292 :
293 : template<class Handler>
294 : const char*
295 : basic_parser<Handler>::
296 : suspend_or_fail(state st)
297 : {
298 : if(BOOST_JSON_LIKELY(
299 : ! ec_ && more_))
300 : {
301 : // suspend
302 : reserve();
303 : st_.push_unchecked(st);
304 : }
305 : return sentinel();
306 : }
307 :
308 : template<class Handler>
309 : const char*
310 56215 : basic_parser<Handler>::
311 : suspend_or_fail(
312 : state st,
313 : std::size_t n)
314 : {
315 56215 : if(BOOST_JSON_LIKELY(
316 : ! ec_ && more_))
317 : {
318 : // suspend
319 35897 : reserve();
320 35897 : st_.push_unchecked(n);
321 35897 : st_.push_unchecked(st);
322 : }
323 56215 : return sentinel();
324 : }
325 :
326 :
327 : template<class Handler>
328 : const char*
329 26260 : basic_parser<Handler>::
330 : fail(const char* p) noexcept
331 : {
332 26260 : BOOST_ASSERT( p != sentinel() );
333 26260 : end_ = p;
334 26260 : return sentinel();
335 : }
336 :
337 : template<class Handler>
338 : const char*
339 10159 : basic_parser<Handler>::
340 : fail(
341 : const char* p,
342 : error ev,
343 : source_location const* loc) noexcept
344 : {
345 10159 : BOOST_ASSERT( p != sentinel() );
346 10159 : end_ = p;
347 10159 : ec_.assign(ev, loc);
348 10159 : return sentinel();
349 : }
350 :
351 : template<class Handler>
352 : const char*
353 13588 : basic_parser<Handler>::
354 : maybe_suspend(
355 : const char* p,
356 : state st)
357 : {
358 13588 : if( p != sentinel() )
359 11650 : end_ = p;
360 13588 : if(BOOST_JSON_LIKELY(more_))
361 : {
362 : // suspend
363 13313 : reserve();
364 13313 : st_.push_unchecked(st);
365 : }
366 13588 : return sentinel();
367 : }
368 :
369 : template<class Handler>
370 : const char*
371 41284 : basic_parser<Handler>::
372 : maybe_suspend(
373 : const char* p,
374 : state st,
375 : std::size_t n)
376 : {
377 41284 : BOOST_ASSERT( p != sentinel() );
378 41284 : end_ = p;
379 41284 : if(BOOST_JSON_LIKELY(more_))
380 : {
381 : // suspend
382 40876 : reserve();
383 40876 : st_.push_unchecked(n);
384 40876 : st_.push_unchecked(st);
385 : }
386 41284 : return sentinel();
387 : }
388 :
389 : template<class Handler>
390 : const char*
391 2278 : basic_parser<Handler>::
392 : maybe_suspend(
393 : const char* p,
394 : state st,
395 : const number& num)
396 : {
397 2278 : BOOST_ASSERT( p != sentinel() );
398 2278 : end_ = p;
399 2278 : if(BOOST_JSON_LIKELY(more_))
400 : {
401 : // suspend
402 2278 : num_ = num;
403 2278 : reserve();
404 2278 : st_.push_unchecked(st);;
405 : }
406 2278 : return sentinel();
407 : }
408 :
409 : template<class Handler>
410 : const char*
411 101323 : basic_parser<Handler>::
412 : suspend(
413 : const char* p,
414 : state st)
415 : {
416 101323 : BOOST_ASSERT( p != sentinel() );
417 101323 : end_ = p;
418 : // suspend
419 101323 : reserve();
420 101323 : st_.push_unchecked(st);
421 101323 : return sentinel();
422 : }
423 :
424 : template<class Handler>
425 : const char*
426 8433887 : basic_parser<Handler>::
427 : suspend(
428 : const char* p,
429 : state st,
430 : const number& num)
431 : {
432 8433887 : BOOST_ASSERT( p != sentinel() );
433 8433887 : end_ = p;
434 : // suspend
435 8433887 : num_ = num;
436 8433887 : reserve();
437 8433887 : st_.push_unchecked(st);
438 8433887 : return sentinel();
439 : }
440 :
441 : template<class Handler>
442 : template<
443 : bool StackEmpty_/*,
444 : bool Terminal_*/>
445 : const char*
446 21827 : basic_parser<Handler>::
447 : parse_comment(const char* p,
448 : std::integral_constant<bool, StackEmpty_> stack_empty,
449 : /*std::integral_constant<bool, Terminal_>*/ bool terminal)
450 : {
451 21827 : detail::const_stream_wrapper cs(p, end_);
452 21827 : const char* start = cs.begin();
453 : std::size_t remain;
454 21827 : if(! stack_empty && ! st_.empty())
455 : {
456 : state st;
457 3575 : st_.pop(st);
458 3575 : switch(st)
459 : {
460 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
461 541 : case state::com1: goto do_com1;
462 2380 : case state::com2: goto do_com2;
463 438 : case state::com3: goto do_com3;
464 216 : case state::com4: goto do_com4;
465 : }
466 : }
467 18252 : BOOST_ASSERT(*cs == '/');
468 18252 : ++cs;
469 18793 : do_com1:
470 18793 : if(BOOST_JSON_UNLIKELY(! cs))
471 558 : return maybe_suspend(cs.begin(), state::com1);
472 18235 : switch(*cs)
473 : {
474 5 : default:
475 : {
476 : BOOST_STATIC_CONSTEXPR source_location loc
477 : = BOOST_CURRENT_LOCATION;
478 5 : return fail(cs.begin(), error::syntax, &loc);
479 : }
480 10546 : case '/':
481 10546 : ++cs;
482 12926 : do_com2:
483 : // KRYSTIAN TODO: this is a mess, we have to fix this
484 12926 : remain = cs.remain();
485 25852 : cs = remain ? static_cast<const char*>(
486 12926 : std::memchr(cs.begin(), '\n', remain)) : sentinel();
487 12926 : if(! cs.begin())
488 2197 : cs = sentinel();
489 12926 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
490 : {
491 : // if the doc does not terminate
492 : // with a newline, treat it as the
493 : // end of the comment
494 2631 : if(terminal && ! more_)
495 : {
496 39 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
497 : {start, cs.remain(start)}, ec_)))
498 2 : return fail(cs.end());
499 35 : return cs.end();
500 : }
501 2592 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
502 : {start, cs.remain(start)}, ec_)))
503 96 : return fail(cs.end());
504 2400 : if(terminal)
505 106 : return suspend(cs.end(), state::com2);
506 2294 : return maybe_suspend(cs.end(), state::com2);
507 : }
508 10295 : break;
509 1684 : case '*':
510 : do
511 : {
512 9368 : ++cs;
513 9806 : do_com3:
514 : // KRYSTIAN TODO: this is a mess, we have to fix this
515 9806 : remain = cs.remain();
516 19612 : cs = remain ? static_cast<const char*>(
517 9806 : std::memchr(cs.begin(), '*', remain)) : sentinel();
518 9806 : if(! cs.begin())
519 242 : cs = sentinel();
520 : // stopped inside a c comment
521 9806 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
522 : {
523 503 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
524 : {start, cs.remain(start)}, ec_)))
525 30 : return fail(cs.end());
526 443 : return maybe_suspend(cs.end(), state::com3);
527 : }
528 : // found a asterisk, check if the next char is a slash
529 9303 : ++cs;
530 9519 : do_com4:
531 9519 : if(BOOST_JSON_UNLIKELY(! cs))
532 : {
533 259 : if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
534 : {start, cs.used(start)}, ec_)))
535 18 : return fail(cs.begin());
536 223 : return maybe_suspend(cs.begin(), state::com4);
537 : }
538 : }
539 9260 : while(*cs != '/');
540 : }
541 17871 : ++cs;
542 17871 : if(BOOST_JSON_UNLIKELY(! h_.on_comment(
543 : {start, cs.used(start)}, ec_)))
544 968 : return fail(cs.begin());
545 15935 : return cs.begin();
546 : }
547 :
548 : template<class Handler>
549 : template<bool StackEmpty_>
550 : const char*
551 10769464 : basic_parser<Handler>::
552 : parse_document(const char* p,
553 : std::integral_constant<bool, StackEmpty_> stack_empty)
554 : {
555 10769464 : detail::const_stream_wrapper cs(p, end_);
556 10769464 : if(! stack_empty && ! st_.empty())
557 : {
558 : state st;
559 8580215 : st_.peek(st);
560 8580215 : switch(st)
561 : {
562 8487572 : default: goto do_doc2;
563 817 : case state::doc1:
564 817 : st_.pop(st);
565 817 : goto do_doc1;
566 91606 : case state::doc3:
567 91606 : st_.pop(st);
568 91606 : goto do_doc3;
569 220 : case state::com1: case state::com2:
570 : case state::com3: case state::com4:
571 220 : goto do_doc4;
572 : }
573 : }
574 2189249 : do_doc1:
575 2190066 : cs = detail::count_whitespace(cs.begin(), cs.end());
576 2190066 : if(BOOST_JSON_UNLIKELY(! cs))
577 851 : return maybe_suspend(cs.begin(), state::doc1);
578 2189215 : do_doc2:
579 10676787 : switch(+opt_.allow_comments |
580 10676787 : (opt_.allow_trailing_commas << 1) |
581 10676787 : (opt_.allow_invalid_utf8 << 2))
582 : {
583 : // no extensions
584 10652965 : default:
585 10652965 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
586 10630559 : break;
587 : // comments
588 13691 : case 1:
589 13691 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
590 11423 : break;
591 : // trailing
592 6710 : case 2:
593 6710 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
594 5117 : break;
595 : // comments & trailing
596 761 : case 3:
597 761 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
598 761 : break;
599 : // skip validation
600 760 : case 4:
601 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
602 760 : break;
603 : // comments & skip validation
604 760 : case 5:
605 760 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
606 760 : break;
607 : // trailing & skip validation
608 760 : case 6:
609 760 : cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
610 760 : break;
611 : // comments & trailing & skip validation
612 380 : case 7:
613 380 : cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
614 380 : break;
615 : }
616 10650520 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
617 : // the appropriate state has already been pushed into stack
618 8524434 : return sentinel();
619 2126086 : do_doc3:
620 2218024 : cs = detail::count_whitespace(cs.begin(), cs.end());
621 2218024 : if(BOOST_JSON_UNLIKELY(! cs))
622 : {
623 2212102 : if(more_)
624 101217 : return suspend(cs.begin(), state::doc3);
625 : }
626 5922 : else if(opt_.allow_comments && *cs == '/')
627 : {
628 536 : do_doc4:
629 756 : cs = parse_comment(cs.begin(), stack_empty, std::true_type());
630 671 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
631 339 : return sentinel();
632 332 : goto do_doc3;
633 : }
634 2116271 : return cs.begin();
635 : }
636 :
637 : template<class Handler>
638 : template<
639 : bool StackEmpty_,
640 : bool AllowComments_/*,
641 : bool AllowTrailing_,
642 : bool AllowBadUTF8_*/>
643 : const char*
644 10794582 : basic_parser<Handler>::
645 : parse_value(const char* p,
646 : std::integral_constant<bool, StackEmpty_> stack_empty,
647 : std::integral_constant<bool, AllowComments_> allow_comments,
648 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
649 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
650 : bool allow_bad_utf16)
651 : {
652 10794582 : if(stack_empty || st_.empty())
653 : {
654 2288592 : loop:
655 2293508 : switch(*p)
656 : {
657 31459 : case '0':
658 31459 : return mp11::mp_with_index<3>(
659 31459 : static_cast<unsigned char>(opt_.numbers),
660 29476 : parse_number_helper<true, '0'>{ this, p });
661 40985 : case '-':
662 40985 : return mp11::mp_with_index<3>(
663 40985 : static_cast<unsigned char>(opt_.numbers),
664 37649 : parse_number_helper<true, '-'>{ this, p });
665 2055921 : case '1': case '2': case '3':
666 : case '4': case '5': case '6':
667 : case '7': case '8': case '9':
668 2055921 : return mp11::mp_with_index<3>(
669 2055921 : static_cast<unsigned char>(opt_.numbers),
670 2051131 : parse_number_helper<true, '+'>{ this, p });
671 11391 : case 'n':
672 11391 : return parse_literal( p, detail::literals_c<detail::literals::null>() );
673 664 : case 't':
674 664 : return parse_literal( p, detail::literals_c<detail::literals::true_>() );
675 722 : case 'f':
676 722 : return parse_literal( p, detail::literals_c<detail::literals::false_>() );
677 1935 : case 'I':
678 1935 : if( !opt_.allow_infinity_and_nan )
679 : {
680 : BOOST_STATIC_CONSTEXPR source_location loc
681 : = BOOST_CURRENT_LOCATION;
682 24 : return fail(p, error::syntax, &loc);
683 : }
684 1911 : return parse_literal( p, detail::literals_c<detail::literals::infinity>() );
685 597 : case 'N':
686 597 : if( !opt_.allow_infinity_and_nan )
687 : {
688 : BOOST_STATIC_CONSTEXPR source_location loc
689 : = BOOST_CURRENT_LOCATION;
690 30 : return fail(p, error::syntax, &loc);
691 : }
692 567 : return parse_literal(p, detail::literals_c<detail::literals::nan>() );
693 47587 : case '"':
694 47587 : return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
695 20677 : case '[':
696 20677 : return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
697 74138 : case '{':
698 74138 : return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
699 6147 : case '/':
700 6147 : if(! allow_comments)
701 : {
702 : BOOST_STATIC_CONSTEXPR source_location loc
703 : = BOOST_CURRENT_LOCATION;
704 284 : return fail(p, error::syntax, &loc);
705 : }
706 5863 : p = parse_comment(p, stack_empty, std::false_type());
707 : // KRYSTIAN NOTE: incomplete takes const_stream, we either
708 : // can add an overload, change the existing one to take a pointer,
709 : // or just leave it as is
710 5624 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
711 605 : return maybe_suspend(p, state::val2);
712 : BOOST_FALLTHROUGH;
713 : case ' ':
714 : case '\t':
715 : case '\n':
716 : case '\r':
717 5035 : p = detail::count_whitespace(p, end_);
718 5035 : if(BOOST_JSON_UNLIKELY(p == end_))
719 119 : return maybe_suspend(p, state::val1);
720 4916 : goto loop;
721 1269 : default:
722 : {
723 : BOOST_STATIC_CONSTEXPR source_location loc
724 : = BOOST_CURRENT_LOCATION;
725 1269 : return fail(p, error::syntax, &loc);
726 : }
727 : }
728 : }
729 8505990 : return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
730 : }
731 :
732 : template<class Handler>
733 : template<
734 : bool AllowComments_/*,
735 : bool AllowTrailing_,
736 : bool AllowBadUTF8_*/>
737 : const char*
738 8505990 : basic_parser<Handler>::
739 : resume_value(const char* p,
740 : std::integral_constant<bool, AllowComments_> allow_comments,
741 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
742 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
743 : bool allow_bad_utf16)
744 : {
745 : state st;
746 8505990 : st_.peek(st);
747 8505990 : switch(st)
748 : {
749 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
750 3848 : case state::lit1:
751 3848 : return parse_literal(p, detail::literals_c<detail::literals::resume>() );
752 :
753 23268 : case state::str1: case state::str2:
754 : case state::str8:
755 23268 : return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
756 :
757 5780 : case state::arr1: case state::arr2:
758 : case state::arr3: case state::arr4:
759 : case state::arr5: case state::arr6:
760 5780 : return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
761 :
762 35074 : case state::obj1: case state::obj2:
763 : case state::obj3: case state::obj4:
764 : case state::obj5: case state::obj6:
765 : case state::obj7: case state::obj8:
766 : case state::obj9: case state::obj10:
767 : case state::obj11:
768 35074 : return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
769 :
770 8436162 : case state::num1: case state::num2:
771 : case state::num3: case state::num4:
772 : case state::num5: case state::num6:
773 : case state::num7: case state::num8:
774 : case state::exp1: case state::exp2:
775 : case state::exp3:
776 8436162 : return mp11::mp_with_index<3>(
777 8436162 : static_cast<unsigned char>(opt_.numbers),
778 8433867 : parse_number_helper<false, 0>{ this, p });
779 :
780 : // KRYSTIAN NOTE: these are special cases
781 112 : case state::val1:
782 : {
783 112 : st_.pop(st);
784 112 : BOOST_ASSERT(st_.empty());
785 112 : p = detail::count_whitespace(p, end_);
786 112 : if(BOOST_JSON_UNLIKELY(p == end_))
787 4 : return maybe_suspend(p, state::val1);
788 108 : return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
789 : }
790 :
791 1676 : case state::val2:
792 : {
793 1676 : st_.pop(st);
794 1676 : p = parse_comment(p, std::false_type(), std::false_type());
795 1656 : if(BOOST_JSON_UNLIKELY(p == sentinel()))
796 1333 : return maybe_suspend(p, state::val2);
797 323 : if(BOOST_JSON_UNLIKELY( p == end_ ))
798 80 : return maybe_suspend(p, state::val3);
799 243 : BOOST_ASSERT(st_.empty());
800 243 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
801 : }
802 :
803 70 : case state::val3:
804 : {
805 70 : st_.pop(st);
806 70 : return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
807 : }
808 : }
809 : }
810 :
811 : template<class Handler>
812 : template<class Literal>
813 : const char*
814 21963 : basic_parser<Handler>::
815 : parse_literal(const char* p, Literal)
816 : {
817 : using L = detail::literals;
818 :
819 : std::size_t cur_lit;
820 : std::size_t offset;
821 :
822 21963 : detail::const_stream_wrapper cs(p, end_);
823 : BOOST_IF_CONSTEXPR( Literal::value != L::resume )
824 : {
825 15278 : constexpr std::size_t index = literal_index(Literal::value);
826 15278 : constexpr char const* literal = detail::literal_strings[index];
827 15278 : constexpr std::size_t sz = detail::literal_sizes[index];
828 :
829 15278 : if(BOOST_JSON_LIKELY( cs.remain() >= sz ))
830 : {
831 12408 : int const cmp = std::memcmp(cs.begin(), literal, sz);
832 12408 : if( cmp != 0 )
833 : {
834 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
835 273 : return fail(cs.begin(), error::syntax, &loc);
836 : }
837 :
838 : BOOST_IF_CONSTEXPR( Literal::value == L::null )
839 : {
840 10789 : if(BOOST_JSON_UNLIKELY(
841 : ! h_.on_null(ec_)))
842 161 : return fail(cs.begin());
843 : }
844 : else BOOST_IF_CONSTEXPR( Literal::value == L::true_ )
845 : {
846 384 : if(BOOST_JSON_UNLIKELY(
847 : ! h_.on_bool(true, ec_)))
848 14 : return fail(cs.begin());
849 : }
850 : else BOOST_IF_CONSTEXPR( Literal::value == L::false_ )
851 : {
852 406 : if(BOOST_JSON_UNLIKELY(
853 : ! h_.on_bool(false, ec_)))
854 13 : return fail(cs.begin());
855 : }
856 : else BOOST_IF_CONSTEXPR( Literal::value == L::infinity )
857 : {
858 277 : if(BOOST_JSON_UNLIKELY(
859 : ! h_.on_double(
860 : std::numeric_limits<double>::infinity(),
861 : string_view(literal, sz),
862 : ec_)))
863 39 : return fail(cs.begin());
864 : }
865 : else BOOST_IF_CONSTEXPR( Literal::value == L::neg_infinity )
866 : {
867 23 : if(BOOST_JSON_UNLIKELY(
868 : ! h_.on_double(
869 : -std::numeric_limits<double>::infinity(),
870 : string_view(literal, sz),
871 : ec_)))
872 3 : return fail(cs.begin());
873 : }
874 : else BOOST_IF_CONSTEXPR( Literal::value == L::nan )
875 : {
876 256 : if(BOOST_JSON_UNLIKELY(
877 : ! h_.on_double(
878 : std::numeric_limits<double>::quiet_NaN(),
879 : string_view(literal, sz),
880 : ec_)))
881 36 : return fail(cs.begin());
882 : }
883 : else
884 : {
885 : BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
886 : }
887 :
888 11607 : cs += sz;
889 11607 : return cs.begin();
890 : }
891 :
892 2870 : offset = 0;
893 2870 : cur_lit = index;
894 : }
895 : else
896 : {
897 : state st;
898 6685 : st_.pop(st);
899 6685 : BOOST_ASSERT( st == state::lit1 );
900 :
901 6685 : cur_lit = cur_lit_;
902 6685 : offset = lit_offset_;
903 : }
904 :
905 9555 : std::size_t const lit_size = detail::literal_sizes[cur_lit];
906 9555 : std::size_t const size = (std::min)( lit_size - offset, cs.remain() );
907 9555 : int cmp = 0;
908 9555 : if(BOOST_JSON_LIKELY( cs.begin() ))
909 9554 : cmp = std::memcmp(
910 9554 : cs.begin(), detail::literal_strings[cur_lit] + offset, size );
911 9555 : if( cmp != 0 )
912 : {
913 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
914 1741 : return fail(cs.begin(), error::syntax, &loc);
915 : }
916 :
917 7814 : if(BOOST_JSON_UNLIKELY( offset + size < lit_size ))
918 : {
919 3914 : BOOST_ASSERT( cur_lit < 256 );
920 3914 : cur_lit_ = static_cast<unsigned char>( cur_lit );
921 3914 : BOOST_ASSERT( offset + size < 256 );
922 3914 : lit_offset_ = static_cast<unsigned char>( offset + size );
923 3914 : return maybe_suspend(cs.begin() + size, state::lit1);
924 : }
925 :
926 3900 : switch( static_cast<L>(cur_lit) )
927 : {
928 472 : case L::null:
929 472 : if(BOOST_JSON_UNLIKELY(
930 : ! h_.on_null(ec_)))
931 61 : return fail(cs.begin());
932 351 : break;
933 152 : case L::true_:
934 152 : if(BOOST_JSON_UNLIKELY(
935 : ! h_.on_bool(true, ec_)))
936 22 : return fail(cs.begin());
937 109 : break;
938 198 : case L::false_:
939 198 : if(BOOST_JSON_UNLIKELY(
940 : ! h_.on_bool(false, ec_)))
941 28 : return fail(cs.begin());
942 142 : break;
943 910 : case L::infinity:
944 910 : if(BOOST_JSON_UNLIKELY(
945 : ! h_.on_double(
946 : std::numeric_limits<double>::infinity(),
947 : string_view(
948 : detail::literal_strings[ literal_index(L::infinity) ],
949 : detail::literal_sizes[ literal_index(L::infinity) ]),
950 : ec_)))
951 147 : return fail(cs.begin());
952 616 : break;
953 1944 : case L::neg_infinity:
954 1944 : if(BOOST_JSON_UNLIKELY(
955 : ! h_.on_double(
956 : -std::numeric_limits<double>::infinity(),
957 : string_view(
958 : detail::literal_strings[ literal_index(L::neg_infinity) ],
959 : detail::literal_sizes[ literal_index(L::neg_infinity) ]),
960 : ec_)))
961 306 : return fail(cs.begin());
962 1332 : break;
963 224 : case L::nan:
964 224 : if(BOOST_JSON_UNLIKELY(
965 : ! h_.on_double(
966 : std::numeric_limits<double>::quiet_NaN(),
967 : string_view(
968 : detail::literal_strings[ literal_index(L::nan) ],
969 : detail::literal_sizes[ literal_index(L::nan) ]),
970 : ec_)))
971 36 : return fail(cs.begin());
972 152 : break;
973 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
974 : }
975 :
976 2702 : cs += size;
977 2702 : return cs.begin();
978 : }
979 :
980 : //----------------------------------------------------------
981 :
982 : template<class Handler>
983 : template<bool StackEmpty_, bool IsKey_>
984 : const char*
985 164348 : basic_parser<Handler>::
986 : parse_string(const char* p,
987 : std::integral_constant<bool, StackEmpty_> stack_empty,
988 : std::integral_constant<bool, IsKey_> is_key,
989 : bool allow_bad_utf8,
990 : bool allow_bad_utf16)
991 : {
992 164348 : detail::const_stream_wrapper cs(p, end_);
993 : std::size_t total;
994 : char const* start;
995 : std::size_t size;
996 164348 : if(! stack_empty && ! st_.empty())
997 : {
998 : state st;
999 35919 : st_.pop(st);
1000 35919 : st_.pop(total);
1001 35919 : switch(st)
1002 : {
1003 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1004 3149 : case state::str2: goto do_str2;
1005 1868 : case state::str8: goto do_str8;
1006 30902 : case state::str1: break;
1007 : }
1008 : }
1009 : else
1010 : {
1011 128429 : BOOST_ASSERT(*cs == '\x22'); // '"'
1012 128429 : ++cs;
1013 128429 : total = 0;
1014 : }
1015 :
1016 167824 : do_str1:
1017 167824 : start = cs.begin();
1018 335648 : cs = allow_bad_utf8?
1019 2177 : detail::count_valid<true>(cs.begin(), cs.end()):
1020 165647 : detail::count_valid<false>(cs.begin(), cs.end());
1021 167824 : size = cs.used(start);
1022 167824 : if(is_key)
1023 : {
1024 46712 : BOOST_ASSERT(total <= Handler::max_key_size);
1025 94023 : if(BOOST_JSON_UNLIKELY(size >
1026 : Handler::max_key_size - total))
1027 : {
1028 : BOOST_STATIC_CONSTEXPR source_location loc
1029 : = BOOST_CURRENT_LOCATION;
1030 3 : return fail(cs.begin(), error::key_too_large, &loc);
1031 : }
1032 : }
1033 : else
1034 : {
1035 38330 : BOOST_ASSERT(total <= Handler::max_string_size);
1036 73801 : if(BOOST_JSON_UNLIKELY(size >
1037 : Handler::max_string_size - total))
1038 : {
1039 : BOOST_STATIC_CONSTEXPR source_location loc
1040 : = BOOST_CURRENT_LOCATION;
1041 3 : return fail(cs.begin(), error::string_too_large, &loc);
1042 : }
1043 : }
1044 167818 : total += size;
1045 167818 : if(BOOST_JSON_UNLIKELY(! cs))
1046 : {
1047 : // call handler if the string isn't empty
1048 33236 : if(BOOST_JSON_LIKELY(size))
1049 : {
1050 : {
1051 30068 : bool r = is_key?
1052 12406 : h_.on_key_part( {start, size}, total, ec_ ):
1053 18996 : h_.on_string_part( {start, size}, total, ec_ );
1054 :
1055 28960 : if(BOOST_JSON_UNLIKELY(!r))
1056 : {
1057 1110 : return fail(cs.begin());
1058 : }
1059 : }
1060 : }
1061 31018 : return maybe_suspend(cs.begin(), state::str1, total);
1062 : }
1063 : // at this point all valid characters have been skipped, so any remaining
1064 : // if there are any more characters, they are either escaped, or incomplete
1065 : // utf8, or invalid utf8
1066 134582 : if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
1067 : {
1068 : // sequence is invalid or incomplete
1069 15081 : if((*cs & 0x80) && !allow_bad_utf8)
1070 : {
1071 3472 : seq_.save(cs.begin(), cs.remain());
1072 3472 : if(BOOST_JSON_UNLIKELY(seq_.complete()))
1073 : {
1074 : BOOST_STATIC_CONSTEXPR source_location loc
1075 : = BOOST_CURRENT_LOCATION;
1076 1557 : return fail(cs.begin(), error::syntax, &loc);
1077 : }
1078 1915 : if(BOOST_JSON_LIKELY(size))
1079 : {
1080 245 : bool const r = is_key?
1081 22 : h_.on_key_part( {start, size}, total, ec_ ):
1082 245 : h_.on_string_part( {start, size}, total, ec_ );
1083 223 : if(BOOST_JSON_UNLIKELY( !r ))
1084 22 : return fail( cs.begin() );
1085 : }
1086 1871 : return maybe_suspend(cs.end(), state::str8, total);
1087 : }
1088 11609 : else if(BOOST_JSON_LIKELY(*cs == '\\'))
1089 : {
1090 : // flush unescaped run from input
1091 11500 : if(BOOST_JSON_LIKELY(size))
1092 : {
1093 4250 : bool const r = is_key?
1094 1226 : h_.on_key_part( {start, size}, total, ec_ ):
1095 3554 : h_.on_string_part( {start, size}, total, ec_ );
1096 3766 : if(BOOST_JSON_UNLIKELY( !r ))
1097 484 : return fail( cs.begin() );
1098 : }
1099 7250 : do_str2:
1100 13681 : cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
1101 12719 : if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
1102 5476 : return suspend_or_fail(state::str2, total);
1103 :
1104 7243 : goto do_str1;
1105 : }
1106 : // illegal control
1107 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1108 109 : return fail(cs.begin(), error::syntax, &loc);
1109 : }
1110 :
1111 : {
1112 119501 : bool r = is_key?
1113 84525 : h_.on_key( {start, size}, total, ec_ ):
1114 41985 : h_.on_string( {start, size}, total, ec_ );
1115 :
1116 115127 : if(BOOST_JSON_UNLIKELY(!r))
1117 : {
1118 4318 : return fail(cs.begin());
1119 : }
1120 : }
1121 :
1122 110809 : ++cs;
1123 110809 : return cs.begin();
1124 :
1125 1868 : do_str8:
1126 1868 : uint8_t needed = seq_.needed();
1127 1868 : if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
1128 4 : return maybe_suspend(cs.end(), state::str8, total);
1129 1864 : if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
1130 : {
1131 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1132 210 : return fail(cs.begin(), error::syntax, &loc);
1133 : }
1134 : {
1135 1654 : std::size_t const n = seq_.length();
1136 : bool r;
1137 1654 : if(is_key)
1138 : {
1139 2 : BOOST_ASSERT(total <= Handler::max_key_size);
1140 2 : if(BOOST_JSON_UNLIKELY(n >
1141 : Handler::max_key_size - total))
1142 : {
1143 : BOOST_STATIC_CONSTEXPR source_location loc
1144 : = BOOST_CURRENT_LOCATION;
1145 1 : return fail(cs.begin(), error::key_too_large, &loc);
1146 : }
1147 1 : total += n;
1148 1 : r = h_.on_key_part( {seq_.data(), n}, total, ec_ );
1149 : }
1150 : else
1151 : {
1152 1 : BOOST_ASSERT(total <= Handler::max_string_size);
1153 1652 : if(BOOST_JSON_UNLIKELY(n >
1154 : Handler::max_string_size - total))
1155 : {
1156 : BOOST_STATIC_CONSTEXPR source_location loc
1157 : = BOOST_CURRENT_LOCATION;
1158 1 : return fail(cs.begin(), error::string_too_large, &loc);
1159 : }
1160 1651 : total += n;
1161 1651 : r = h_.on_string_part( {seq_.data(), n}, total, ec_ );
1162 : }
1163 1451 : if(BOOST_JSON_UNLIKELY( !r ))
1164 201 : return fail( cs.begin() );
1165 : }
1166 1250 : cs += needed;
1167 1250 : goto do_str1;
1168 : }
1169 :
1170 : template<class Handler>
1171 : template<bool StackEmpty_>
1172 : const char*
1173 13681 : basic_parser<Handler>::
1174 : parse_escaped(
1175 : const char* p,
1176 : std::size_t& total,
1177 : std::integral_constant<bool, StackEmpty_> stack_empty,
1178 : bool is_key,
1179 : bool allow_bad_utf16)
1180 : {
1181 13681 : constexpr unsigned urc = 0xFFFD; // Unicode replacement character
1182 13681 : auto const ev_too_large = is_key?
1183 : error::key_too_large : error::string_too_large;
1184 13681 : auto const max_size = is_key?
1185 : Handler::max_key_size : Handler::max_string_size;
1186 : int digit;
1187 :
1188 : //---------------------------------------------------------------
1189 : //
1190 : // To handle escapes, a local temporary buffer accumulates
1191 : // the unescaped result. The algorithm attempts to fill the
1192 : // buffer to capacity before invoking the handler.
1193 : // In some cases the temporary buffer needs to be flushed
1194 : // before it is full:
1195 : // * When the closing double quote is seen
1196 : // * When there in no more input (and more is expected later)
1197 : // A goal of the algorithm is to call the handler as few times
1198 : // as possible. Thus, when the first escape is encountered,
1199 : // the algorithm attempts to fill the temporary buffer first.
1200 : //
1201 13681 : detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1202 :
1203 : // Unescaped JSON is never larger than its escaped version.
1204 : // To efficiently process only what will fit in the temporary buffer,
1205 : // the size of the input stream is temporarily "clipped" to the size
1206 : // of the temporary buffer.
1207 : // handle escaped character
1208 13681 : detail::clipped_const_stream cs(p, end_);
1209 13681 : cs.clip(temp.max_size());
1210 :
1211 13681 : if(! stack_empty && ! st_.empty())
1212 : {
1213 : state st;
1214 3149 : st_.pop(st);
1215 3149 : switch(st)
1216 : {
1217 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1218 528 : case state::str3: goto do_str3;
1219 392 : case state::str4: goto do_str4;
1220 390 : case state::str5: goto do_str5;
1221 389 : case state::str6: goto do_str6;
1222 386 : case state::str7: goto do_str7;
1223 232 : case state::sur1: goto do_sur1;
1224 188 : case state::sur2: goto do_sur2;
1225 164 : case state::sur3: goto do_sur3;
1226 162 : case state::sur4: goto do_sur4;
1227 160 : case state::sur5: goto do_sur5;
1228 158 : case state::sur6: goto do_sur6;
1229 : }
1230 : }
1231 :
1232 3783 : while(true)
1233 : {
1234 14315 : BOOST_ASSERT( temp.capacity() );
1235 14315 : BOOST_ASSERT(*cs == '\\');
1236 14315 : ++cs;
1237 15174 : do_str3:
1238 15379 : if(BOOST_JSON_UNLIKELY(! cs))
1239 : {
1240 562 : if(BOOST_JSON_LIKELY(! temp.empty()))
1241 : {
1242 1 : BOOST_ASSERT(total <= max_size);
1243 101 : if(BOOST_JSON_UNLIKELY(
1244 : temp.size() > max_size - total))
1245 : {
1246 : BOOST_STATIC_CONSTEXPR source_location loc
1247 : = BOOST_CURRENT_LOCATION;
1248 1 : return fail(cs.begin(), ev_too_large, &loc);
1249 : }
1250 100 : total += temp.size();
1251 : {
1252 91 : bool r = is_key
1253 100 : ? h_.on_key_part(temp.get(), total, ec_)
1254 100 : : h_.on_string_part(temp.get(), total, ec_);
1255 :
1256 91 : if(BOOST_JSON_UNLIKELY(!r))
1257 : {
1258 9 : return fail(cs.begin());
1259 : }
1260 : }
1261 82 : temp.clear();
1262 : }
1263 543 : cs.clip(temp.max_size());
1264 543 : if(BOOST_JSON_UNLIKELY(! cs))
1265 543 : return maybe_suspend(cs.begin(), state::str3);
1266 : }
1267 14817 : switch(*cs)
1268 : {
1269 191 : default:
1270 : {
1271 : BOOST_STATIC_CONSTEXPR source_location loc
1272 : = BOOST_CURRENT_LOCATION;
1273 191 : return fail(cs.begin(), error::syntax, &loc);
1274 : }
1275 265 : case '\x22': // '"'
1276 265 : temp.push_back('\x22');
1277 265 : ++cs;
1278 265 : break;
1279 178 : case '\\':
1280 178 : temp.push_back('\\');
1281 178 : ++cs;
1282 178 : break;
1283 96 : case '/':
1284 96 : temp.push_back('/');
1285 96 : ++cs;
1286 96 : break;
1287 112 : case 'b':
1288 112 : temp.push_back('\x08');
1289 112 : ++cs;
1290 112 : break;
1291 108 : case 'f':
1292 108 : temp.push_back('\x0c');
1293 108 : ++cs;
1294 108 : break;
1295 1766 : case 'n':
1296 1766 : temp.push_back('\x0a');
1297 1766 : ++cs;
1298 1766 : break;
1299 146 : case 'r':
1300 146 : temp.push_back('\x0d');
1301 146 : ++cs;
1302 146 : break;
1303 266 : case 't':
1304 266 : temp.push_back('\x09');
1305 266 : ++cs;
1306 266 : break;
1307 11689 : case 'u':
1308 : // utf16 escape
1309 : //
1310 : // fast path only when the buffer
1311 : // is large enough for 2 surrogates
1312 11689 : if(BOOST_JSON_LIKELY(cs.remain() > 10))
1313 : {
1314 : // KRYSTIAN TODO: this could be done
1315 : // with fewer instructions
1316 11394 : digit = detail::load_little_endian<4>(
1317 5697 : cs.begin() + 1);
1318 5697 : int d4 = detail::hex_digit(static_cast<
1319 5697 : unsigned char>(digit >> 24));
1320 5697 : int d3 = detail::hex_digit(static_cast<
1321 5697 : unsigned char>(digit >> 16));
1322 5697 : int d2 = detail::hex_digit(static_cast<
1323 5697 : unsigned char>(digit >> 8));
1324 5697 : int d1 = detail::hex_digit(static_cast<
1325 : unsigned char>(digit));
1326 5697 : if(BOOST_JSON_UNLIKELY(
1327 : (d1 | d2 | d3 | d4) == -1))
1328 : {
1329 60 : if(d1 != -1)
1330 45 : ++cs;
1331 60 : if(d2 != -1)
1332 30 : ++cs;
1333 60 : if(d3 != -1)
1334 15 : ++cs;
1335 : BOOST_STATIC_CONSTEXPR source_location loc
1336 : = BOOST_CURRENT_LOCATION;
1337 60 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1338 : }
1339 : // 32 bit unicode scalar value
1340 5637 : unsigned u1 =
1341 5637 : (d1 << 12) + (d2 << 8) +
1342 5637 : (d3 << 4) + d4;
1343 : // valid unicode scalar values are
1344 : // [0, D7FF] and [E000, 10FFFF]
1345 : // values within this range are valid utf-8
1346 : // code points and invalid leading surrogates.
1347 5637 : if(BOOST_JSON_LIKELY(
1348 : u1 < 0xd800 || u1 > 0xdfff))
1349 : {
1350 1340 : cs += 5;
1351 1340 : temp.append_utf8(u1);
1352 1340 : break;
1353 : }
1354 4297 : if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1355 : {
1356 : // If it's an illegal leading surrogate and
1357 : // the parser does not allow it, return an error.
1358 707 : if(!allow_bad_utf16)
1359 : {
1360 : BOOST_STATIC_CONSTEXPR source_location loc
1361 : = BOOST_CURRENT_LOCATION;
1362 122 : return fail(cs.begin(), error::illegal_leading_surrogate,
1363 122 : &loc);
1364 : }
1365 : // Otherwise, append the Unicode replacement character
1366 : else
1367 : {
1368 585 : cs += 5;
1369 585 : temp.append_utf8(urc);
1370 585 : break;
1371 : }
1372 : }
1373 3590 : cs += 5;
1374 : // KRYSTIAN TODO: this can be a two byte load
1375 : // and a single comparison. We lose error information,
1376 : // but it's faster.
1377 3590 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1378 : {
1379 : // If the next character is not a backslash and
1380 : // the parser does not allow it, return a syntax error.
1381 156 : if(!allow_bad_utf16)
1382 : {
1383 : BOOST_STATIC_CONSTEXPR source_location loc
1384 : = BOOST_CURRENT_LOCATION;
1385 15 : return fail(cs.begin(), error::syntax, &loc);
1386 : }
1387 : // Otherwise, append the Unicode replacement character since
1388 : // the first code point is a valid leading surrogate
1389 : else
1390 : {
1391 141 : temp.append_utf8(urc);
1392 141 : break;
1393 : }
1394 : }
1395 3434 : ++cs;
1396 3434 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1397 : {
1398 220 : if (!allow_bad_utf16)
1399 : {
1400 : BOOST_STATIC_CONSTEXPR source_location loc
1401 : = BOOST_CURRENT_LOCATION;
1402 15 : return fail(cs.begin(), error::syntax, &loc);
1403 : }
1404 : // Otherwise, append the Unicode replacement character since
1405 : // the first code point is a valid leading surrogate
1406 : else
1407 : {
1408 205 : temp.append_utf8(urc);
1409 205 : goto do_str3;
1410 : }
1411 : }
1412 3214 : ++cs;
1413 3214 : digit = detail::load_little_endian<4>(cs.begin());
1414 3214 : d4 = detail::hex_digit(static_cast<
1415 3214 : unsigned char>(digit >> 24));
1416 3214 : d3 = detail::hex_digit(static_cast<
1417 3214 : unsigned char>(digit >> 16));
1418 3214 : d2 = detail::hex_digit(static_cast<
1419 3214 : unsigned char>(digit >> 8));
1420 3214 : d1 = detail::hex_digit(static_cast<
1421 : unsigned char>(digit));
1422 3214 : if(BOOST_JSON_UNLIKELY(
1423 : (d1 | d2 | d3 | d4) == -1))
1424 : {
1425 90 : if(d1 != -1)
1426 75 : ++cs;
1427 90 : if(d2 != -1)
1428 45 : ++cs;
1429 90 : if(d3 != -1)
1430 15 : ++cs;
1431 : BOOST_STATIC_CONSTEXPR source_location loc
1432 : = BOOST_CURRENT_LOCATION;
1433 90 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1434 : }
1435 3124 : unsigned u2 =
1436 3124 : (d1 << 12) + (d2 << 8) +
1437 3124 : (d3 << 4) + d4;
1438 : // Check if the second code point is a valid trailing surrogate.
1439 : // Valid trailing surrogates are [DC00, DFFF]
1440 3124 : if(BOOST_JSON_UNLIKELY(
1441 : u2 < 0xdc00 || u2 > 0xdfff))
1442 : {
1443 : // If not valid and the parser does not allow it, return an error.
1444 1353 : if(!allow_bad_utf16)
1445 : {
1446 : BOOST_STATIC_CONSTEXPR source_location loc
1447 : = BOOST_CURRENT_LOCATION;
1448 136 : return fail(cs.begin(), error::illegal_trailing_surrogate,
1449 136 : &loc);
1450 : }
1451 : // Append the replacement character for the
1452 : // first leading surrogate.
1453 1217 : cs += 4;
1454 1217 : temp.append_utf8(urc);
1455 : // Check if the second code point is a
1456 : // valid unicode scalar value (invalid leading
1457 : // or trailing surrogate)
1458 1217 : if (u2 < 0xd800 || u2 > 0xdbff)
1459 : {
1460 524 : temp.append_utf8(u2);
1461 524 : break;
1462 : }
1463 : // If it is a valid leading surrogate
1464 : else
1465 : {
1466 693 : u1_ = u2;
1467 693 : goto do_sur1;
1468 : }
1469 : }
1470 1771 : cs += 4;
1471 : // Calculate the Unicode code point from the surrogate pair and
1472 : // append the UTF-8 representation.
1473 1771 : unsigned cp =
1474 1771 : ((u1 - 0xd800) << 10) +
1475 : ((u2 - 0xdc00)) +
1476 : 0x10000;
1477 : // utf-16 surrogate pair
1478 1771 : temp.append_utf8(cp);
1479 1771 : break;
1480 : }
1481 : // flush
1482 5992 : if(BOOST_JSON_LIKELY(! temp.empty()))
1483 : {
1484 4 : BOOST_ASSERT(total <= max_size);
1485 1723 : if(BOOST_JSON_UNLIKELY(
1486 : temp.size() > max_size - total))
1487 : {
1488 : BOOST_STATIC_CONSTEXPR source_location loc
1489 : = BOOST_CURRENT_LOCATION;
1490 1 : return fail(cs.begin(), ev_too_large, &loc);
1491 : }
1492 1722 : total += temp.size();
1493 : {
1494 1582 : bool r = is_key
1495 1722 : ? h_.on_key_part(temp.get(), total, ec_)
1496 1722 : : h_.on_string_part(temp.get(), total, ec_);
1497 :
1498 1582 : if(BOOST_JSON_UNLIKELY(!r))
1499 : {
1500 140 : return fail(cs.begin());
1501 : }
1502 : }
1503 1442 : temp.clear();
1504 1442 : cs.clip(temp.max_size());
1505 : }
1506 5711 : ++cs;
1507 : // utf-16 escape
1508 6103 : do_str4:
1509 6103 : if(BOOST_JSON_UNLIKELY(! cs))
1510 392 : return maybe_suspend(cs.begin(), state::str4);
1511 5711 : digit = detail::hex_digit(*cs);
1512 5711 : if(BOOST_JSON_UNLIKELY(digit == -1))
1513 : {
1514 : BOOST_STATIC_CONSTEXPR source_location loc
1515 : = BOOST_CURRENT_LOCATION;
1516 50 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1517 : }
1518 5661 : ++cs;
1519 5661 : u1_ = digit << 12;
1520 6051 : do_str5:
1521 6051 : if(BOOST_JSON_UNLIKELY(! cs))
1522 390 : return maybe_suspend(cs.begin(), state::str5);
1523 5661 : digit = detail::hex_digit(*cs);
1524 5661 : 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 5641 : ++cs;
1531 5641 : u1_ += digit << 8;
1532 6030 : do_str6:
1533 6030 : if(BOOST_JSON_UNLIKELY(! cs))
1534 389 : return maybe_suspend(cs.begin(), state::str6);
1535 5641 : digit = detail::hex_digit(*cs);
1536 5641 : if(BOOST_JSON_UNLIKELY(digit == -1))
1537 : {
1538 : BOOST_STATIC_CONSTEXPR source_location loc
1539 : = BOOST_CURRENT_LOCATION;
1540 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1541 : }
1542 5621 : ++cs;
1543 5621 : u1_ += digit << 4;
1544 6007 : do_str7:
1545 6007 : if(BOOST_JSON_UNLIKELY(! cs))
1546 386 : return maybe_suspend(cs.begin(), state::str7);
1547 5621 : digit = detail::hex_digit(*cs);
1548 5621 : if(BOOST_JSON_UNLIKELY(digit == -1))
1549 : {
1550 : BOOST_STATIC_CONSTEXPR source_location loc
1551 : = BOOST_CURRENT_LOCATION;
1552 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1553 : }
1554 5586 : ++cs;
1555 5586 : u1_ += digit;
1556 5586 : if(BOOST_JSON_LIKELY(
1557 : u1_ < 0xd800 || u1_ > 0xdfff))
1558 : {
1559 1434 : BOOST_ASSERT(temp.empty());
1560 : // utf-8 codepoint
1561 1434 : temp.append_utf8(u1_);
1562 1434 : break;
1563 : }
1564 4152 : if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1565 : {
1566 : // If it's an illegal leading surrogate and
1567 : // the parser does not allow it, return an error.
1568 1585 : if(!allow_bad_utf16)
1569 : {
1570 : BOOST_STATIC_CONSTEXPR source_location loc
1571 : = BOOST_CURRENT_LOCATION;
1572 209 : return fail(cs.begin(), error::illegal_leading_surrogate, &loc);
1573 : }
1574 : // Otherwise, append the Unicode replacement character
1575 : else
1576 : {
1577 1376 : BOOST_ASSERT(temp.empty());
1578 1376 : temp.append_utf8(urc);
1579 1376 : break;
1580 : }
1581 : }
1582 2567 : do_sur1:
1583 3792 : if(BOOST_JSON_UNLIKELY(! cs))
1584 232 : return maybe_suspend(cs.begin(), state::sur1);
1585 3560 : if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1586 : {
1587 : // If the next character is not a backslash and
1588 : // the parser does not allow it, return a syntax error.
1589 952 : if(!allow_bad_utf16)
1590 : {
1591 : BOOST_STATIC_CONSTEXPR source_location loc
1592 : = BOOST_CURRENT_LOCATION;
1593 149 : return fail(cs.begin(), error::syntax, &loc);
1594 : }
1595 : // Otherwise, append the Unicode replacement character since
1596 : // the first code point is a valid leading surrogate
1597 : else
1598 : {
1599 803 : temp.append_utf8(urc);
1600 803 : break;
1601 : }
1602 : }
1603 2608 : ++cs;
1604 2796 : do_sur2:
1605 2796 : if(BOOST_JSON_UNLIKELY(! cs))
1606 188 : return maybe_suspend(cs.begin(), state::sur2);
1607 2608 : if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1608 : {
1609 396 : if (!allow_bad_utf16)
1610 : {
1611 : BOOST_STATIC_CONSTEXPR source_location loc
1612 : = BOOST_CURRENT_LOCATION;
1613 65 : return fail(cs.begin(), error::syntax, &loc);
1614 : }
1615 : // Otherwise, append the Unicode replacement character since
1616 : // the first code point is a valid leading surrogate
1617 : else
1618 : {
1619 331 : temp.append_utf8(urc);
1620 331 : goto do_str3;
1621 : }
1622 : }
1623 2212 : ++cs;
1624 2376 : do_sur3:
1625 2376 : if(BOOST_JSON_UNLIKELY(! cs))
1626 164 : return maybe_suspend(cs.begin(), state::sur3);
1627 2212 : digit = detail::hex_digit(*cs);
1628 2212 : 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 2177 : ++cs;
1635 2177 : u2_ = digit << 12;
1636 2339 : do_sur4:
1637 2339 : if(BOOST_JSON_UNLIKELY(! cs))
1638 162 : return maybe_suspend(cs.begin(), state::sur4);
1639 2177 : digit = detail::hex_digit(*cs);
1640 2177 : if(BOOST_JSON_UNLIKELY(digit == -1))
1641 : {
1642 : BOOST_STATIC_CONSTEXPR source_location loc
1643 : = BOOST_CURRENT_LOCATION;
1644 35 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1645 : }
1646 2142 : ++cs;
1647 2142 : u2_ += digit << 8;
1648 2302 : do_sur5:
1649 2302 : if(BOOST_JSON_UNLIKELY(! cs))
1650 160 : return maybe_suspend(cs.begin(), state::sur5);
1651 2142 : digit = detail::hex_digit(*cs);
1652 2142 : 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 2122 : ++cs;
1659 2122 : u2_ += digit << 4;
1660 2280 : do_sur6:
1661 2280 : if(BOOST_JSON_UNLIKELY(! cs))
1662 158 : return maybe_suspend(cs.begin(), state::sur6);
1663 2122 : digit = detail::hex_digit(*cs);
1664 2122 : if(BOOST_JSON_UNLIKELY(digit == -1))
1665 : {
1666 : BOOST_STATIC_CONSTEXPR source_location loc
1667 : = BOOST_CURRENT_LOCATION;
1668 20 : return fail(cs.begin(), error::expected_hex_digit, &loc);
1669 : }
1670 2102 : ++cs;
1671 2102 : u2_ += digit;
1672 : // Check if the second code point is a valid trailing surrogate.
1673 : // Valid trailing surrogates are [DC00, DFFF]
1674 2102 : if(BOOST_JSON_UNLIKELY(
1675 : u2_ < 0xdc00 || u2_ > 0xdfff))
1676 : {
1677 : // If not valid and the parser does not allow it, return an error.
1678 580 : if(!allow_bad_utf16)
1679 : {
1680 : BOOST_STATIC_CONSTEXPR source_location loc
1681 : = BOOST_CURRENT_LOCATION;
1682 60 : return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1683 : }
1684 : // Append the replacement character for the
1685 : // first leading surrogate.
1686 520 : temp.append_utf8(urc);
1687 : // Check if the second code point is a
1688 : // valid unicode scalar value (invalid leading
1689 : // or trailing surrogate)
1690 520 : if (u2_ < 0xd800 || u2_ > 0xdbff)
1691 : {
1692 220 : temp.append_utf8(u2_);
1693 220 : break;
1694 : }
1695 : // If it is a valid leading surrogate
1696 : else
1697 : {
1698 300 : u1_ = u2_;
1699 300 : goto do_sur1;
1700 : }
1701 : }
1702 : // Calculate the Unicode code point from the surrogate pair and
1703 : // append the UTF-8 representation.
1704 1522 : unsigned cp =
1705 1522 : ((u1_ - 0xd800) << 10) +
1706 1522 : ((u2_ - 0xdc00)) +
1707 : 0x10000;
1708 : // utf-16 surrogate pair
1709 1522 : temp.append_utf8(cp);
1710 : }
1711 :
1712 : // flush
1713 12653 : if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
1714 8870 : break;
1715 : }
1716 :
1717 8870 : if(BOOST_JSON_LIKELY( temp.size() ))
1718 : {
1719 434 : BOOST_ASSERT(total <= max_size);
1720 8870 : if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
1721 : {
1722 : BOOST_STATIC_CONSTEXPR source_location loc
1723 : = BOOST_CURRENT_LOCATION;
1724 1 : return fail(cs.begin(), ev_too_large, &loc);
1725 : }
1726 :
1727 8869 : total += temp.size();
1728 8056 : bool const r = is_key
1729 8869 : ? h_.on_key_part(temp.get(), total, ec_)
1730 8152 : : h_.on_string_part(temp.get(), total, ec_);
1731 8056 : if(BOOST_JSON_UNLIKELY( !r ))
1732 813 : return fail( cs.begin() );
1733 : }
1734 :
1735 7243 : return cs.begin();
1736 : }
1737 :
1738 : //----------------------------------------------------------
1739 :
1740 : template<class Handler>
1741 : template<
1742 : bool StackEmpty_,
1743 : bool AllowComments_/*,
1744 : bool AllowTrailing_,
1745 : bool AllowBadUTF8_*/>
1746 : const char*
1747 109212 : basic_parser<Handler>::
1748 : parse_object(const char* p,
1749 : std::integral_constant<bool, StackEmpty_> stack_empty,
1750 : std::integral_constant<bool, AllowComments_> allow_comments,
1751 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1752 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1753 : bool allow_bad_utf16)
1754 : {
1755 109212 : detail::const_stream_wrapper cs(p, end_);
1756 : std::size_t size;
1757 109212 : if(! stack_empty && ! st_.empty())
1758 : {
1759 : // resume
1760 : state st;
1761 35074 : st_.pop(st);
1762 35074 : st_.pop(size);
1763 35074 : switch(st)
1764 : {
1765 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1766 1596 : case state::obj1: goto do_obj1;
1767 235 : case state::obj2: goto do_obj2;
1768 12651 : case state::obj3: goto do_obj3;
1769 1692 : case state::obj4: goto do_obj4;
1770 251 : case state::obj5: goto do_obj5;
1771 1593 : case state::obj6: goto do_obj6;
1772 15453 : case state::obj7: goto do_obj7;
1773 427 : case state::obj8: goto do_obj8;
1774 661 : case state::obj9: goto do_obj9;
1775 181 : case state::obj10: goto do_obj10;
1776 334 : case state::obj11: goto do_obj11;
1777 : }
1778 : }
1779 74138 : BOOST_ASSERT(*cs == '{');
1780 74138 : size = 0;
1781 74138 : if(BOOST_JSON_UNLIKELY(! depth_))
1782 : {
1783 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1784 3 : return fail(cs.begin(), error::too_deep, &loc);
1785 : }
1786 74135 : --depth_;
1787 74135 : if(BOOST_JSON_UNLIKELY(
1788 : ! h_.on_object_begin(ec_)))
1789 2040 : return fail(cs.begin());
1790 70057 : ++cs;
1791 : // object:
1792 : // '{' *ws '}'
1793 : // '{' *ws string *ws ':' *ws value *ws *[ ',' *ws string *ws ':' *ws value *ws ] '}'
1794 73624 : do_obj1:
1795 73624 : cs = detail::count_whitespace(cs.begin(), cs.end());
1796 73624 : if(BOOST_JSON_UNLIKELY(! cs))
1797 1630 : return maybe_suspend(cs.begin(), state::obj1, size);
1798 71994 : if(BOOST_JSON_LIKELY(*cs != '}'))
1799 : {
1800 69095 : if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
1801 : {
1802 2411 : if(allow_comments && *cs == '/')
1803 : {
1804 2139 : do_obj2:
1805 2374 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1806 2290 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1807 319 : return suspend_or_fail(state::obj2, size);
1808 1971 : goto do_obj1;
1809 : }
1810 : BOOST_STATIC_CONSTEXPR source_location loc
1811 : = BOOST_CURRENT_LOCATION;
1812 272 : return fail(cs.begin(), error::syntax, &loc);
1813 : }
1814 66684 : loop:
1815 80843 : if(BOOST_JSON_UNLIKELY(++size >
1816 : Handler::max_object_size))
1817 : {
1818 : BOOST_STATIC_CONSTEXPR source_location loc
1819 : = BOOST_CURRENT_LOCATION;
1820 1 : return fail(cs.begin(), error::object_too_large, &loc);
1821 : }
1822 80842 : do_obj3:
1823 93493 : cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
1824 90537 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1825 15596 : return suspend_or_fail(state::obj3, size);
1826 74941 : do_obj4:
1827 79104 : cs = detail::count_whitespace(cs.begin(), cs.end());
1828 79104 : if(BOOST_JSON_UNLIKELY(! cs))
1829 1707 : return maybe_suspend(cs.begin(), state::obj4, size);
1830 77397 : if(BOOST_JSON_UNLIKELY(*cs != ':'))
1831 : {
1832 2925 : if(allow_comments && *cs == '/')
1833 : {
1834 2779 : do_obj5:
1835 3030 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1836 2876 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1837 405 : return suspend_or_fail(state::obj5, size);
1838 2471 : goto do_obj4;
1839 : }
1840 : BOOST_STATIC_CONSTEXPR source_location loc
1841 : = BOOST_CURRENT_LOCATION;
1842 146 : return fail(cs.begin(), error::syntax, &loc);
1843 : }
1844 74472 : ++cs;
1845 76065 : do_obj6:
1846 76065 : cs = detail::count_whitespace(cs.begin(), cs.end());
1847 76065 : if(BOOST_JSON_UNLIKELY(! cs))
1848 1624 : return maybe_suspend(cs.begin(), state::obj6, size);
1849 74441 : do_obj7:
1850 89894 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1851 82545 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1852 23598 : return suspend_or_fail(state::obj7, size);
1853 58947 : do_obj8:
1854 61210 : cs = detail::count_whitespace(cs.begin(), cs.end());
1855 61210 : if(BOOST_JSON_UNLIKELY(! cs))
1856 442 : return maybe_suspend(cs.begin(), state::obj8, size);
1857 60768 : if(BOOST_JSON_LIKELY(*cs == ','))
1858 : {
1859 17799 : ++cs;
1860 19715 : do_obj9:
1861 19715 : cs = detail::count_whitespace(cs.begin(), cs.end());
1862 19715 : if(BOOST_JSON_UNLIKELY(! cs))
1863 691 : return maybe_suspend(cs.begin(), state::obj9, size);
1864 :
1865 : // loop for next element
1866 19024 : if(BOOST_JSON_LIKELY(*cs == '\x22'))
1867 14159 : goto loop;
1868 4865 : if(! allow_trailing || *cs != '}')
1869 : {
1870 1644 : if(allow_comments && *cs == '/')
1871 : {
1872 1433 : do_obj10:
1873 1614 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1874 1525 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1875 270 : return suspend_or_fail(state::obj10, size);
1876 1255 : goto do_obj9;
1877 : }
1878 : BOOST_STATIC_CONSTEXPR source_location loc
1879 : = BOOST_CURRENT_LOCATION;
1880 211 : return fail(cs.begin(), error::syntax, &loc);
1881 : }
1882 : }
1883 42969 : else if(BOOST_JSON_UNLIKELY(*cs != '}'))
1884 : {
1885 2325 : if(allow_comments && *cs == '/')
1886 : {
1887 2172 : do_obj11:
1888 2506 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1889 2338 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1890 502 : return suspend_or_fail(state::obj11, size);
1891 1836 : goto do_obj8;
1892 : }
1893 : BOOST_STATIC_CONSTEXPR source_location loc
1894 : = BOOST_CURRENT_LOCATION;
1895 153 : return fail(cs.begin(), error::syntax, &loc);
1896 : }
1897 : // got closing brace, fall through
1898 : }
1899 46764 : if(BOOST_JSON_UNLIKELY(
1900 : ! h_.on_object_end(size, ec_)))
1901 1502 : return fail(cs.begin());
1902 43721 : ++depth_;
1903 43721 : ++cs;
1904 43721 : return cs.begin();
1905 : }
1906 :
1907 : //----------------------------------------------------------
1908 :
1909 : template<class Handler>
1910 : template<
1911 : bool StackEmpty_,
1912 : bool AllowComments_/*,
1913 : bool AllowTrailing_,
1914 : bool AllowBadUTF8_*/>
1915 : const char*
1916 26457 : basic_parser<Handler>::
1917 : parse_array(const char* p,
1918 : std::integral_constant<bool, StackEmpty_> stack_empty,
1919 : std::integral_constant<bool, AllowComments_> allow_comments,
1920 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
1921 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
1922 : bool allow_bad_utf16)
1923 : {
1924 26457 : detail::const_stream_wrapper cs(p, end_);
1925 : std::size_t size;
1926 26457 : if(! stack_empty && ! st_.empty())
1927 : {
1928 : // resume
1929 : state st;
1930 5780 : st_.pop(st);
1931 5780 : st_.pop(size);
1932 5780 : switch(st)
1933 : {
1934 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
1935 1061 : case state::arr1: goto do_arr1;
1936 384 : case state::arr2: goto do_arr2;
1937 2965 : case state::arr3: goto do_arr3;
1938 396 : case state::arr4: goto do_arr4;
1939 680 : case state::arr5: goto do_arr5;
1940 294 : case state::arr6: goto do_arr6;
1941 : }
1942 : }
1943 20677 : BOOST_ASSERT(*cs == '[');
1944 20677 : size = 0;
1945 20677 : if(BOOST_JSON_UNLIKELY(! depth_))
1946 : {
1947 : BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1948 34 : return fail(cs.begin(), error::too_deep, &loc);
1949 : }
1950 20643 : --depth_;
1951 20643 : if(BOOST_JSON_UNLIKELY(
1952 : ! h_.on_array_begin(ec_)))
1953 812 : return fail(cs.begin());
1954 19025 : ++cs;
1955 : // array:
1956 : // '[' *ws ']'
1957 : // '[' *ws value *ws *[ ',' *ws value *ws ] ']'
1958 21619 : do_arr1:
1959 21619 : cs = detail::count_whitespace(cs.begin(), cs.end());
1960 21619 : if(BOOST_JSON_UNLIKELY(! cs))
1961 1082 : return maybe_suspend(cs.begin(), state::arr1, size);
1962 20537 : if(BOOST_JSON_LIKELY(*cs != ']'))
1963 : {
1964 18782 : loop:
1965 26305 : if(allow_comments && *cs == '/')
1966 : {
1967 1789 : do_arr2:
1968 2173 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1969 2045 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1970 512 : return suspend_or_fail(state::arr2, size);
1971 1533 : goto do_arr1;
1972 : }
1973 24516 : if(BOOST_JSON_UNLIKELY(++size >
1974 : Handler::max_array_size))
1975 : {
1976 : BOOST_STATIC_CONSTEXPR source_location loc
1977 : = BOOST_CURRENT_LOCATION;
1978 1 : return fail(cs.begin(), error::array_too_large, &loc);
1979 : }
1980 24515 : do_arr3:
1981 : // array is not empty, value required
1982 27480 : cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1983 24849 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1984 9079 : return suspend_or_fail(state::arr3, size);
1985 15770 : do_arr4:
1986 17396 : cs = detail::count_whitespace(cs.begin(), cs.end());
1987 17396 : if(BOOST_JSON_UNLIKELY(! cs))
1988 505 : return maybe_suspend(cs.begin(), state::arr4, size);
1989 16891 : if(BOOST_JSON_LIKELY(*cs == ','))
1990 : {
1991 9236 : ++cs;
1992 9916 : do_arr5:
1993 9916 : cs = detail::count_whitespace(cs.begin(), cs.end());
1994 9916 : if(BOOST_JSON_UNLIKELY(! cs))
1995 710 : return maybe_suspend(cs.begin(), state::arr5, size);
1996 : // loop for next element
1997 9206 : if(! allow_trailing || *cs != ']')
1998 7523 : goto loop;
1999 : }
2000 7655 : else if(BOOST_JSON_UNLIKELY(*cs != ']'))
2001 : {
2002 1969 : if(allow_comments && *cs == '/')
2003 : {
2004 1541 : do_arr6:
2005 1835 : cs = parse_comment(cs.begin(), stack_empty, std::false_type());
2006 1688 : if(BOOST_JSON_UNLIKELY(incomplete(cs)))
2007 458 : return suspend_or_fail(state::arr6, size);
2008 1230 : goto do_arr4;
2009 : }
2010 : BOOST_STATIC_CONSTEXPR source_location loc
2011 : = BOOST_CURRENT_LOCATION;
2012 428 : return fail(cs.begin(), error::syntax, &loc);
2013 : }
2014 : // got closing bracket; fall through
2015 : }
2016 9124 : if(BOOST_JSON_UNLIKELY(
2017 : ! h_.on_array_end(size, ec_)))
2018 549 : return fail(cs.begin());
2019 7996 : ++depth_;
2020 7996 : ++cs;
2021 7996 : return cs.begin();
2022 : }
2023 :
2024 : //----------------------------------------------------------
2025 :
2026 : template<class Handler>
2027 : template<bool StackEmpty_, char First_>
2028 : char const*
2029 9483477 : basic_parser<Handler>::
2030 : parse_number(
2031 : char const* p,
2032 : std::integral_constant<bool, StackEmpty_> stack_empty,
2033 : std::integral_constant<char, First_> first)
2034 : {
2035 : // only one of these will be true if we are not resuming
2036 : // if negative then !zero_first && !nonzero_first
2037 : // if zero_first then !nonzero_first && !negative
2038 : // if nonzero_first then !zero_first && !negative
2039 9483477 : bool const negative = first == '-';
2040 9483477 : bool const zero_first = first == '0';
2041 9483477 : bool const nonzero_first = first == '+';
2042 9483477 : detail::const_stream_wrapper cs(p, end_);
2043 : number num;
2044 9483477 : const char* begin = cs.begin();
2045 9483477 : if(stack_empty || st_.empty())
2046 : {
2047 1071486 : num.bias = 0;
2048 1071486 : num.exp = 0;
2049 1071486 : num.frac = false;
2050 1071486 : num.neg = negative;
2051 :
2052 : //----------------------------------
2053 : //
2054 : // '-'
2055 : // leading minus sign
2056 : //
2057 1071486 : BOOST_ASSERT(cs);
2058 : if(negative)
2059 17385 : ++cs;
2060 :
2061 : // fast path
2062 1071486 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
2063 : {
2064 : int n1;
2065 :
2066 5149 : if( nonzero_first ||
2067 5149 : (negative && *cs != '0') )
2068 : {
2069 1005623 : n1 = detail::count_digits( cs.begin() );
2070 1005623 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2071 :
2072 1063 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2073 : {
2074 9 : return parse_literal(
2075 : p - 1,
2076 8 : detail::literals_c<detail::literals::neg_infinity>());
2077 : }
2078 :
2079 1054 : if( ! nonzero_first && n1 == 0 )
2080 : {
2081 : // digit required
2082 : BOOST_STATIC_CONSTEXPR source_location loc
2083 : = BOOST_CURRENT_LOCATION;
2084 2 : return fail(cs.begin(), error::syntax, &loc);
2085 : }
2086 :
2087 1005612 : num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
2088 1005612 : cs += n1;
2089 :
2090 : // integer or floating-point with
2091 : // >= 16 leading digits
2092 1005612 : if( n1 == 16 )
2093 : {
2094 1001029 : goto do_num2;
2095 : }
2096 : }
2097 : else
2098 : {
2099 : // 0. floating-point or 0e integer
2100 10733 : num.mant = 0;
2101 10733 : n1 = 0;
2102 10733 : ++cs;
2103 : }
2104 :
2105 : {
2106 15316 : const char c = *cs;
2107 15316 : if(c != '.')
2108 : {
2109 6613 : if((c | 32) == 'e')
2110 : {
2111 3318 : ++cs;
2112 3318 : goto do_exp1;
2113 : }
2114 : BOOST_IF_CONSTEXPR( negative )
2115 20 : num.mant = ~num.mant + 1;
2116 3295 : goto finish_signed;
2117 : }
2118 : }
2119 :
2120 : // floating-point number
2121 :
2122 8703 : ++cs;
2123 :
2124 8703 : int n2 = detail::count_digits( cs.begin() );
2125 8703 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2126 :
2127 8703 : if( n2 == 0 )
2128 : {
2129 : // digit required
2130 : BOOST_STATIC_CONSTEXPR source_location loc
2131 : = BOOST_CURRENT_LOCATION;
2132 3 : return fail(cs.begin(), error::syntax, &loc);
2133 : }
2134 :
2135 : // floating-point mantissa overflow
2136 8700 : if( n1 + n2 >= 19 )
2137 : {
2138 64 : goto do_num7;
2139 : }
2140 :
2141 8636 : num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
2142 :
2143 8636 : BOOST_ASSERT(num.bias == 0);
2144 :
2145 8636 : num.bias -= n2;
2146 :
2147 8636 : cs += n2;
2148 :
2149 8636 : char ch = *cs;
2150 :
2151 8636 : if( (ch | 32) == 'e' )
2152 : {
2153 110 : ++cs;
2154 110 : goto do_exp1;
2155 : }
2156 8526 : else if( ch >= '0' && ch <= '9' )
2157 : {
2158 5017 : goto do_num8;
2159 : }
2160 :
2161 3509 : goto finish_dub;
2162 : }
2163 : }
2164 : else
2165 : {
2166 8411991 : num = num_;
2167 : state st;
2168 8411991 : st_.pop(st);
2169 8411991 : switch(st)
2170 : {
2171 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
2172 475 : case state::num1: goto do_num1;
2173 6049 : case state::num2: goto do_num2;
2174 4195100 : case state::num3: goto do_num3;
2175 48 : case state::num4: goto do_num4;
2176 741 : case state::num5: goto do_num5;
2177 474 : case state::num6: goto do_num6;
2178 422 : case state::num7: goto do_num7;
2179 4201807 : case state::num8: goto do_num8;
2180 385 : case state::exp1: goto do_exp1;
2181 131 : case state::exp2: goto do_exp2;
2182 6359 : case state::exp3: goto do_exp3;
2183 : }
2184 : }
2185 :
2186 : //----------------------------------
2187 : //
2188 : // DIGIT
2189 : // first digit
2190 : //
2191 55605 : do_num1:
2192 12711 : if(zero_first || nonzero_first ||
2193 12711 : BOOST_JSON_LIKELY(cs))
2194 : {
2195 55010 : char const c = *cs;
2196 : if(zero_first)
2197 : {
2198 7236 : ++cs;
2199 7236 : num.mant = 0;
2200 7236 : goto do_num6;
2201 : }
2202 12116 : else if(nonzero_first || BOOST_JSON_LIKELY(
2203 : c >= '1' && c <= '9'))
2204 : {
2205 41088 : ++cs;
2206 41088 : num.mant = c - '0';
2207 : }
2208 6686 : else if(BOOST_JSON_UNLIKELY(
2209 : c == '0'))
2210 : {
2211 5491 : ++cs;
2212 5491 : num.mant = 0;
2213 5491 : goto do_num6;
2214 : }
2215 1195 : else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
2216 : {
2217 1007 : st_.push(state::lit1);
2218 1007 : cur_lit_ = literal_index(detail::literals::neg_infinity);
2219 1007 : lit_offset_ = 1;
2220 1007 : return parse_literal(
2221 961 : cs.begin(), detail::literals_c<detail::literals::resume>() );
2222 : }
2223 : else
2224 : {
2225 : BOOST_STATIC_CONSTEXPR source_location loc
2226 : = BOOST_CURRENT_LOCATION;
2227 188 : return fail(cs.begin(), error::syntax, &loc);
2228 : }
2229 : }
2230 : else
2231 : {
2232 595 : if(BOOST_JSON_UNLIKELY(
2233 : ! h_.on_number_part(
2234 : {begin, cs.used(begin)}, ec_)))
2235 60 : return fail(cs.begin());
2236 :
2237 475 : return maybe_suspend(
2238 475 : cs.begin(), state::num1, num);
2239 : }
2240 :
2241 : //----------------------------------
2242 : //
2243 : // 1*DIGIT
2244 : // significant digits left of decimal
2245 : //
2246 1048166 : do_num2:
2247 1042685 : if(negative || (!stack_empty && num.neg))
2248 : {
2249 21876 : for(;;)
2250 : {
2251 28820 : if(BOOST_JSON_UNLIKELY(! cs))
2252 : {
2253 1857 : if(BOOST_JSON_UNLIKELY(more_))
2254 : {
2255 1405 : if(BOOST_JSON_UNLIKELY(
2256 : ! h_.on_number_part(
2257 : {begin, cs.used(begin)}, ec_)))
2258 69 : return fail(cs.begin());
2259 :
2260 1267 : return suspend(cs.begin(), state::num2, num);
2261 : }
2262 452 : goto finish_int;
2263 : }
2264 26963 : char const c = *cs;
2265 26963 : if(BOOST_JSON_LIKELY(
2266 : c >= '0' && c <= '9'))
2267 : {
2268 22699 : ++cs;
2269 : // 9223372036854775808 INT64_MIN
2270 22699 : if( num.mant > 922337203685477580 || (
2271 21984 : num.mant == 922337203685477580 && c > '8'))
2272 : break;
2273 21876 : num.mant = 10 * num.mant + ( c - '0' );
2274 21876 : continue;
2275 : }
2276 4264 : goto do_num6; // [.eE]
2277 : }
2278 : }
2279 : else
2280 : {
2281 3480940 : for(;;)
2282 : {
2283 4522162 : if(BOOST_JSON_UNLIKELY(! cs))
2284 : {
2285 6241 : if(BOOST_JSON_UNLIKELY(more_))
2286 : {
2287 5628 : if(BOOST_JSON_UNLIKELY(
2288 : ! h_.on_number_part(
2289 : {begin, cs.used(begin)}, ec_)))
2290 426 : return fail(cs.begin());
2291 :
2292 4782 : return suspend(cs.begin(), state::num2, num);
2293 : }
2294 613 : goto finish_int;
2295 : }
2296 4515921 : char const c = *cs;
2297 4515921 : if(BOOST_JSON_LIKELY(
2298 : c >= '0' && c <= '9'))
2299 : {
2300 3484632 : ++cs;
2301 : // 18446744073709551615 UINT64_MAX
2302 3484632 : if( num.mant > 1844674407370955161 || (
2303 3481362 : num.mant == 1844674407370955161 && c > '5'))
2304 : break;
2305 3480940 : num.mant = 10 * num.mant + ( c - '0' );
2306 : }
2307 : else
2308 : {
2309 1031289 : goto do_num6; // [.eE]
2310 : }
2311 : }
2312 : }
2313 4515 : ++num.bias;
2314 :
2315 : //----------------------------------
2316 : //
2317 : // 1*DIGIT
2318 : // non-significant digits left of decimal
2319 : //
2320 4199615 : do_num3:
2321 4294978208 : for(;;)
2322 : {
2323 4299177823 : if(BOOST_JSON_UNLIKELY(! cs))
2324 : {
2325 4195827 : if(BOOST_JSON_UNLIKELY(more_))
2326 : {
2327 4195194 : if(BOOST_JSON_UNLIKELY(
2328 : ! h_.on_number_part(
2329 : {begin, cs.used(begin)}, ec_)))
2330 47 : return fail(cs.begin());
2331 :
2332 4195100 : return suspend(cs.begin(), state::num3, num);
2333 : }
2334 633 : goto finish_dub;
2335 : }
2336 4294981996 : char const c = *cs;
2337 4294981996 : if(BOOST_JSON_UNLIKELY(
2338 : c >= '0' && c <= '9'))
2339 : {
2340 4294978209 : if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
2341 : {
2342 : BOOST_STATIC_CONSTEXPR source_location loc
2343 : = BOOST_CURRENT_LOCATION;
2344 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2345 : }
2346 4294978208 : ++cs;
2347 4294978208 : ++num.bias;
2348 : }
2349 3787 : else if(BOOST_JSON_LIKELY(
2350 : c == '.'))
2351 : {
2352 1796 : ++cs;
2353 1796 : break;
2354 : }
2355 1991 : else if((c | 32) == 'e')
2356 : {
2357 642 : ++cs;
2358 642 : goto do_exp1;
2359 : }
2360 : else
2361 : {
2362 1349 : goto finish_dub;
2363 : }
2364 : }
2365 :
2366 : //----------------------------------
2367 : //
2368 : // DIGIT
2369 : // first non-significant digit
2370 : // to the right of decimal
2371 : //
2372 1844 : do_num4:
2373 : {
2374 1844 : if(BOOST_JSON_UNLIKELY(! cs))
2375 : {
2376 60 : if(BOOST_JSON_UNLIKELY(
2377 : ! h_.on_number_part(
2378 : {begin, cs.used(begin)}, ec_)))
2379 6 : return fail(cs.begin());
2380 :
2381 48 : return maybe_suspend(
2382 48 : cs.begin(), state::num4, num);
2383 : }
2384 1784 : char const c = *cs;
2385 1784 : if(BOOST_JSON_LIKELY(
2386 : //static_cast<unsigned char>(c - '0') < 10))
2387 : c >= '0' && c <= '9'))
2388 : {
2389 1717 : ++cs;
2390 : }
2391 : else
2392 : {
2393 : // digit required
2394 : BOOST_STATIC_CONSTEXPR source_location loc
2395 : = BOOST_CURRENT_LOCATION;
2396 67 : return fail(cs.begin(), error::syntax, &loc);
2397 : }
2398 : }
2399 :
2400 : //----------------------------------
2401 : //
2402 : // 1*DIGIT
2403 : // non-significant digits
2404 : // to the right of decimal
2405 : //
2406 1003880 : do_num5:
2407 18406185 : for(;;)
2408 : {
2409 19410065 : if(BOOST_JSON_UNLIKELY(! cs))
2410 : {
2411 1541 : if(BOOST_JSON_UNLIKELY(more_))
2412 : {
2413 781 : if(BOOST_JSON_UNLIKELY(
2414 : ! h_.on_number_part(
2415 : {begin, cs.used(begin)}, ec_)))
2416 20 : return fail(cs.begin());
2417 :
2418 741 : return suspend(cs.begin(), state::num5, num);
2419 : }
2420 760 : goto finish_dub;
2421 : }
2422 19408524 : char const c = *cs;
2423 19408524 : if(BOOST_JSON_LIKELY(
2424 : c >= '0' && c <= '9'))
2425 : {
2426 18406185 : ++cs;
2427 : }
2428 1002339 : else if((c | 32) == 'e')
2429 : {
2430 1000472 : ++cs;
2431 1000472 : goto do_exp1;
2432 : }
2433 : else
2434 : {
2435 1867 : goto finish_dub;
2436 : }
2437 : }
2438 :
2439 : //----------------------------------
2440 : //
2441 : // [.eE]
2442 : //
2443 1048754 : do_num6:
2444 : {
2445 1048754 : if(BOOST_JSON_UNLIKELY(! cs))
2446 : {
2447 606 : if(BOOST_JSON_UNLIKELY(more_))
2448 : {
2449 559 : if(BOOST_JSON_UNLIKELY(
2450 : ! h_.on_number_part(
2451 : {begin, cs.used(begin)}, ec_)))
2452 42 : return fail(cs.begin());
2453 :
2454 475 : return suspend(cs.begin(), state::num6, num);
2455 : }
2456 47 : goto finish_int;
2457 : }
2458 1048148 : char const c = *cs;
2459 1048148 : if(BOOST_JSON_LIKELY(
2460 : c == '.'))
2461 : {
2462 1011194 : ++cs;
2463 : }
2464 36954 : else if((c | 32) == 'e')
2465 : {
2466 7595 : ++cs;
2467 7595 : goto do_exp1;
2468 : }
2469 : else
2470 : {
2471 29359 : goto finish_int;
2472 : }
2473 : }
2474 :
2475 : //----------------------------------
2476 : //
2477 : // DIGIT
2478 : // first significant digit
2479 : // to the right of decimal
2480 : //
2481 1011680 : do_num7:
2482 : {
2483 1011680 : if(BOOST_JSON_UNLIKELY(! cs))
2484 : {
2485 497 : if(BOOST_JSON_UNLIKELY(more_))
2486 : {
2487 493 : if(BOOST_JSON_UNLIKELY(
2488 : ! h_.on_number_part(
2489 : {begin, cs.used(begin)}, ec_)))
2490 35 : return fail(cs.begin());
2491 :
2492 423 : return suspend(cs.begin(), state::num7, num);
2493 : }
2494 : // digit required
2495 : BOOST_STATIC_CONSTEXPR source_location loc
2496 : = BOOST_CURRENT_LOCATION;
2497 4 : return fail(cs.begin(), error::syntax, &loc);
2498 : }
2499 1011183 : char const c = *cs;
2500 1011183 : if(BOOST_JSON_UNLIKELY(
2501 : c < '0' || c > '9'))
2502 : {
2503 : // digit required
2504 : BOOST_STATIC_CONSTEXPR source_location loc
2505 : = BOOST_CURRENT_LOCATION;
2506 169 : return fail(cs.begin(), error::syntax, &loc);
2507 : }
2508 : }
2509 :
2510 : //----------------------------------
2511 : //
2512 : // 1*DIGIT
2513 : // significant digits
2514 : // to the right of decimal
2515 : //
2516 5217838 : do_num8:
2517 4297156220 : for(;;)
2518 : {
2519 4302374058 : if(BOOST_JSON_UNLIKELY(! cs))
2520 : {
2521 4203159 : if(BOOST_JSON_UNLIKELY(more_))
2522 : {
2523 4201942 : if(BOOST_JSON_UNLIKELY(
2524 : ! h_.on_number_part(
2525 : {begin, cs.used(begin)}, ec_)))
2526 67 : return fail(cs.begin());
2527 :
2528 4201808 : return suspend(cs.begin(), state::num8, num);
2529 : }
2530 1217 : goto finish_dub;
2531 : }
2532 4298170899 : char const c = *cs;
2533 4298170899 : if(BOOST_JSON_LIKELY(
2534 : c >= '0' && c <= '9'))
2535 : {
2536 4298157643 : ++cs;
2537 4298157643 : if(BOOST_JSON_LIKELY( num.mant <= 9007199254740991 )) // 2^53-1
2538 : {
2539 4297156221 : if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
2540 : {
2541 : BOOST_STATIC_CONSTEXPR source_location loc
2542 : = BOOST_CURRENT_LOCATION;
2543 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2544 : }
2545 4297156220 : --num.bias;
2546 4297156220 : num.mant = 10 * num.mant + ( c - '0' );
2547 : }
2548 : else
2549 : {
2550 1001422 : goto do_num5;
2551 : }
2552 : }
2553 13256 : else if((c | 32) == 'e')
2554 : {
2555 8606 : ++cs;
2556 8606 : goto do_exp1;
2557 : }
2558 : else
2559 : {
2560 4650 : goto finish_dub;
2561 : }
2562 : }
2563 :
2564 : //----------------------------------
2565 : //
2566 : // *[+-]
2567 : //
2568 1021128 : do_exp1:
2569 1021128 : if(BOOST_JSON_UNLIKELY(! cs))
2570 : {
2571 483 : if(BOOST_JSON_UNLIKELY(
2572 : ! h_.on_number_part(
2573 : {begin, cs.used(begin)}, ec_)))
2574 49 : return fail(cs.begin());
2575 :
2576 385 : return maybe_suspend(
2577 385 : cs.begin(), state::exp1, num);
2578 : }
2579 1020645 : if(*cs == '+')
2580 : {
2581 2364 : ++cs;
2582 : }
2583 1018281 : else if(*cs == '-')
2584 : {
2585 502089 : ++cs;
2586 502089 : num.frac = true;
2587 : }
2588 :
2589 : //----------------------------------
2590 : //
2591 : // DIGIT
2592 : // first digit of the exponent
2593 : //
2594 516192 : do_exp2:
2595 : {
2596 1020776 : if(BOOST_JSON_UNLIKELY(! cs))
2597 : {
2598 180 : if(BOOST_JSON_UNLIKELY(more_))
2599 : {
2600 171 : if(BOOST_JSON_UNLIKELY(
2601 : ! h_.on_number_part(
2602 : {begin, cs.used(begin)}, ec_)))
2603 20 : return fail(cs.begin());
2604 :
2605 131 : return suspend(cs.begin(), state::exp2, num);
2606 : }
2607 : // digit required
2608 : BOOST_STATIC_CONSTEXPR source_location loc
2609 : = BOOST_CURRENT_LOCATION;
2610 9 : return fail(cs.begin(), error::syntax, &loc);
2611 : }
2612 1020596 : char const c = *cs;
2613 1020596 : if(BOOST_JSON_UNLIKELY(
2614 : c < '0' || c > '9'))
2615 : {
2616 : // digit required
2617 : BOOST_STATIC_CONSTEXPR source_location loc
2618 : = BOOST_CURRENT_LOCATION;
2619 508 : return fail(cs.begin(), error::syntax, &loc);
2620 : }
2621 1020088 : ++cs;
2622 1020088 : num.exp = c - '0';
2623 : }
2624 :
2625 : //----------------------------------
2626 : //
2627 : // 1*DIGIT
2628 : // subsequent digits in the exponent
2629 : //
2630 1026447 : do_exp3:
2631 2740361 : for(;;)
2632 : {
2633 3766808 : if(BOOST_JSON_UNLIKELY(! cs))
2634 : {
2635 1011428 : if(BOOST_JSON_UNLIKELY(more_))
2636 : {
2637 6531 : if(BOOST_JSON_UNLIKELY(
2638 : ! h_.on_number_part(
2639 : {begin, cs.used(begin)}, ec_)))
2640 86 : return fail(cs.begin());
2641 :
2642 6359 : return suspend(cs.begin(), state::exp3, num);
2643 : }
2644 : }
2645 : else
2646 : {
2647 2755380 : char const c = *cs;
2648 2755380 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2649 : {
2650 2740361 : if(BOOST_JSON_UNLIKELY(
2651 : // 2147483647 INT_MAX
2652 : num.exp > 214748364 ||
2653 : (num.exp == 214748364 && c > '7')
2654 : ))
2655 3855 : num.exp = INT_MAX;
2656 : else
2657 2736506 : num.exp = 10 * num.exp + ( c - '0' );
2658 :
2659 2740361 : ++cs;
2660 2740361 : continue;
2661 : }
2662 : }
2663 1019916 : BOOST_ASSERT(num.exp >= 0);
2664 1019916 : if ( num.frac )
2665 : {
2666 501953 : if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
2667 : {
2668 : // if exponent overflowed, bias is a very large negative
2669 : // number, and mantissa isn't zero, then we cannot parse the
2670 : // number correctly
2671 92 : if(BOOST_JSON_UNLIKELY(
2672 : (num.exp == INT_MAX) &&
2673 : (num.bias < 0) &&
2674 : (num.exp + num.bias < 308) &&
2675 : num.mant ))
2676 : {
2677 : BOOST_STATIC_CONSTEXPR source_location loc
2678 : = BOOST_CURRENT_LOCATION;
2679 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2680 : }
2681 :
2682 91 : num.bias = 0;
2683 91 : num.exp = INT_MAX;
2684 : }
2685 : }
2686 517963 : else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
2687 : {
2688 : // if exponent overflowed, bias is a very large positive number,
2689 : // and mantissa isn't zero, then we cannot parse the
2690 : // number correctly
2691 194 : if(BOOST_JSON_UNLIKELY(
2692 : (num.exp == INT_MAX) &&
2693 : (num.bias > 0) &&
2694 : (num.exp - num.bias < 308) &&
2695 : num.mant ))
2696 : {
2697 : BOOST_STATIC_CONSTEXPR source_location loc
2698 : = BOOST_CURRENT_LOCATION;
2699 1 : return fail(cs.begin(), error::exponent_overflow, &loc);
2700 : }
2701 :
2702 193 : num.bias = 0;
2703 193 : num.exp = INT_MAX;
2704 : }
2705 1019914 : goto finish_dub;
2706 : }
2707 :
2708 30471 : finish_int:
2709 28542 : if(negative || (!stack_empty && num.neg))
2710 : {
2711 2531 : if(BOOST_JSON_UNLIKELY(
2712 : ! h_.on_int64(static_cast<
2713 : int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
2714 310 : return fail(cs.begin());
2715 1913 : return cs.begin();
2716 : }
2717 27940 : if(num.mant <= INT64_MAX)
2718 : {
2719 27639 : finish_signed:
2720 30914 : if(BOOST_JSON_UNLIKELY(
2721 : ! h_.on_int64(static_cast<
2722 : int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
2723 2267 : return fail(cs.begin());
2724 26387 : return cs.begin();
2725 : }
2726 321 : if(BOOST_JSON_UNLIKELY(
2727 : ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
2728 35 : return fail(cs.begin());
2729 254 : return cs.begin();
2730 1033899 : finish_dub:
2731 : double d;
2732 1033899 : std::size_t const size = cs.used(begin);
2733 1033899 : d = detail::dec_to_float(
2734 : num.mant,
2735 531947 : num.bias + (num.frac ?
2736 501952 : -num.exp : num.exp),
2737 1033899 : num.neg);
2738 1033899 : if(BOOST_JSON_UNLIKELY(
2739 : ! h_.on_double(d, {begin, size}, ec_)))
2740 1935 : return fail(cs.begin());
2741 1030029 : return cs.begin();
2742 : }
2743 :
2744 : template<class Handler>
2745 : template<bool StackEmpty_, char First_>
2746 : char const*
2747 1040553 : basic_parser<Handler>::
2748 : parse_number_precise(
2749 : char const* p,
2750 : std::integral_constant<bool, StackEmpty_> stack_empty,
2751 : std::integral_constant<char, First_> first)
2752 : {
2753 : // only one of these will be true if we are not resuming
2754 : // if negative then !zero_first && !nonzero_first
2755 : // if zero_first then !nonzero_first && !negative
2756 : // if nonzero_first then !zero_first && !negative
2757 1040553 : bool const negative = first == '-';
2758 1040553 : bool const zero_first = first == '0';
2759 1040553 : bool const nonzero_first = first == '+';
2760 1040553 : detail::const_stream_wrapper cs(p, end_);
2761 : number num;
2762 1040553 : const char* begin = cs.begin();
2763 1040553 : if(stack_empty || st_.empty())
2764 : {
2765 1028466 : num_buf_.clear();
2766 1028466 : num.neg = negative;
2767 :
2768 : // '-'
2769 : // leading minus sign
2770 1028466 : BOOST_ASSERT(cs);
2771 : if(negative)
2772 11802 : ++cs;
2773 :
2774 : // fast path
2775 1028466 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
2776 : {
2777 : int n1;
2778 :
2779 2433 : if( nonzero_first || (negative && *cs != '0') )
2780 : {
2781 1000950 : n1 = detail::count_digits( cs.begin() );
2782 1000950 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2783 :
2784 396 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2785 : {
2786 7 : return parse_literal(
2787 : p - 1,
2788 6 : detail::literals_c<detail::literals::neg_infinity>());
2789 : }
2790 :
2791 389 : if( ! nonzero_first && n1 == 0 )
2792 : {
2793 : // digit required
2794 : BOOST_STATIC_CONSTEXPR source_location loc
2795 : = BOOST_CURRENT_LOCATION;
2796 2 : return fail(cs.begin(), error::syntax, &loc);
2797 : }
2798 :
2799 1000941 : num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
2800 :
2801 1000941 : cs += n1;
2802 :
2803 : // integer or floating-point with
2804 : // >= 16 leading digits
2805 1000941 : if( n1 == 16 )
2806 : {
2807 1000222 : goto do_num2;
2808 : }
2809 : }
2810 : else
2811 : {
2812 : // 0. floating-point or 0e integer
2813 5295 : num.mant = 0;
2814 5295 : n1 = 0;
2815 5295 : ++cs;
2816 : }
2817 :
2818 : {
2819 6014 : char const c = *cs;
2820 6014 : if(c != '.')
2821 : {
2822 1693 : if( (c | 32) == 'e' )
2823 : {
2824 1644 : ++cs;
2825 1644 : goto do_exp1;
2826 : }
2827 : BOOST_IF_CONSTEXPR( negative )
2828 4 : num.mant = ~num.mant + 1;
2829 49 : goto finish_signed;
2830 : }
2831 : }
2832 :
2833 : // floating-point number
2834 :
2835 4321 : ++cs;
2836 :
2837 4321 : int n2 = detail::count_digits( cs.begin() );
2838 4321 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2839 :
2840 4321 : if( n2 == 0 )
2841 : {
2842 : // digit required
2843 : BOOST_STATIC_CONSTEXPR source_location loc
2844 : = BOOST_CURRENT_LOCATION;
2845 3 : return fail(cs.begin(), error::syntax, &loc);
2846 : }
2847 :
2848 : // floating-point mantissa overflow
2849 4318 : if( n1 + n2 >= 19 )
2850 : {
2851 64 : goto do_num7;
2852 : }
2853 :
2854 4254 : cs += n2;
2855 :
2856 4254 : char ch = *cs;
2857 :
2858 4254 : if( (ch | 32) == 'e' )
2859 : {
2860 23 : ++cs;
2861 23 : goto do_exp1;
2862 : }
2863 4231 : else if( ch >= '0' && ch <= '9' )
2864 : {
2865 2501 : goto do_num8;
2866 : }
2867 :
2868 1730 : goto finish_dub;
2869 : }
2870 : }
2871 : else
2872 : {
2873 12087 : num = num_;
2874 : state st;
2875 12087 : st_.pop(st);
2876 12087 : switch(st)
2877 : {
2878 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
2879 361 : case state::num1: goto do_num1;
2880 2428 : case state::num2: goto do_num2;
2881 394 : case state::num3: goto do_num3;
2882 335 : case state::num6: goto do_num6;
2883 338 : case state::num7: goto do_num7;
2884 4342 : case state::num8: goto do_num8;
2885 324 : case state::exp1: goto do_exp1;
2886 116 : case state::exp2: goto do_exp2;
2887 3449 : case state::exp3: goto do_exp3;
2888 : }
2889 : }
2890 :
2891 : // DIGIT
2892 : // first digit
2893 22582 : do_num1:
2894 9730 : if( zero_first || nonzero_first || BOOST_JSON_LIKELY(cs) )
2895 : {
2896 22101 : char const c = *cs;
2897 : if(zero_first)
2898 : {
2899 5531 : ++cs;
2900 5531 : num.mant = 0;
2901 5531 : goto do_num6;
2902 : }
2903 9249 : else if( nonzero_first || BOOST_JSON_LIKELY(c >= '1' && c <= '9') )
2904 : {
2905 11213 : ++cs;
2906 11213 : num.mant = c - '0';
2907 : }
2908 5357 : else if(BOOST_JSON_UNLIKELY( c == '0' ))
2909 : {
2910 4310 : ++cs;
2911 4310 : num.mant = 0;
2912 4310 : goto do_num6;
2913 : }
2914 1047 : else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
2915 : {
2916 915 : st_.push(state::lit1);
2917 915 : cur_lit_ = literal_index(detail::literals::neg_infinity);
2918 915 : lit_offset_ = 1;
2919 915 : return parse_literal(
2920 869 : cs.begin(), detail::literals_c<detail::literals::resume>() );
2921 : }
2922 : else
2923 : {
2924 : BOOST_STATIC_CONSTEXPR source_location loc
2925 : = BOOST_CURRENT_LOCATION;
2926 132 : return fail(cs.begin(), error::syntax, &loc);
2927 : }
2928 : }
2929 : else
2930 : {
2931 481 : if(BOOST_JSON_UNLIKELY(
2932 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
2933 60 : return fail(cs.begin());
2934 :
2935 361 : num_buf_.append( begin, cs.used(begin) );
2936 361 : return maybe_suspend(cs.begin(), state::num1, num);
2937 : }
2938 :
2939 : // 1*DIGIT
2940 : // significant digits left of decimal
2941 1013863 : do_num2:
2942 1010103 : if( negative || (!stack_empty && num.neg) )
2943 : {
2944 10681 : for(;;)
2945 : {
2946 15060 : if(BOOST_JSON_UNLIKELY( !cs ))
2947 : {
2948 722 : if(BOOST_JSON_UNLIKELY( more_ ))
2949 : {
2950 625 : if(BOOST_JSON_UNLIKELY(
2951 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
2952 69 : return fail(cs.begin());
2953 :
2954 487 : num_buf_.append( begin, cs.used(begin) );
2955 487 : return suspend(cs.begin(), state::num2, num);
2956 : }
2957 97 : goto finish_int;
2958 : }
2959 14338 : char const c = *cs;
2960 14338 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2961 : {
2962 10925 : ++cs;
2963 : // 9223372036854775808 INT64_MIN
2964 10925 : if( num.mant > 922337203685477580 || (
2965 10681 : num.mant == 922337203685477580 && c > '8'))
2966 : break;
2967 10681 : num.mant = 10 * num.mant + ( c - '0' );
2968 10681 : continue;
2969 : }
2970 3413 : goto do_num6; // [.eE]
2971 : }
2972 : }
2973 : else
2974 : {
2975 3458262 : for(;;)
2976 : {
2977 4467746 : if(BOOST_JSON_UNLIKELY( !cs ))
2978 : {
2979 2604 : if(BOOST_JSON_UNLIKELY( more_ ))
2980 : {
2981 2513 : if(BOOST_JSON_UNLIKELY(
2982 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
2983 286 : return fail(cs.begin());
2984 :
2985 1941 : num_buf_.append( begin, cs.used(begin) );
2986 1941 : return suspend(cs.begin(), state::num2, num);
2987 : }
2988 91 : goto finish_int;
2989 : }
2990 4465142 : char const c = *cs;
2991 4465142 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2992 : {
2993 3460729 : ++cs;
2994 : // 18446744073709551615 UINT64_MAX
2995 3460729 : if( num.mant > 1844674407370955161 || (
2996 3458419 : num.mant == 1844674407370955161 && c > '5'))
2997 : break;
2998 3458262 : num.mant = 10 * num.mant + ( c - '0' );
2999 : }
3000 : else
3001 : {
3002 1004413 : goto do_num6; // [.eE]
3003 : }
3004 : }
3005 : }
3006 :
3007 : // 1*DIGIT
3008 : // non-significant digits left of decimal
3009 3105 : do_num3:
3010 7852 : for(;;)
3011 : {
3012 10957 : if(BOOST_JSON_UNLIKELY( !cs ))
3013 : {
3014 735 : if(BOOST_JSON_UNLIKELY( more_ ))
3015 : {
3016 488 : if(BOOST_JSON_UNLIKELY(
3017 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3018 47 : return fail(cs.begin());
3019 :
3020 394 : num_buf_.append( begin, cs.used(begin) );
3021 394 : return suspend(cs.begin(), state::num3, num);
3022 : }
3023 247 : goto finish_dub;
3024 : }
3025 10222 : char const c = *cs;
3026 10222 : if(BOOST_JSON_UNLIKELY( c >= '0' && c <= '9' ))
3027 : {
3028 7852 : ++cs;
3029 : }
3030 : else
3031 : {
3032 2370 : goto do_num6; // [.eE]
3033 : }
3034 : }
3035 :
3036 : // [.eE]
3037 1020372 : do_num6:
3038 : {
3039 1020372 : if(BOOST_JSON_UNLIKELY( !cs ))
3040 : {
3041 420 : if(BOOST_JSON_UNLIKELY( more_ ))
3042 : {
3043 419 : if(BOOST_JSON_UNLIKELY(
3044 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3045 42 : return fail(cs.begin());
3046 :
3047 335 : num_buf_.append( begin, cs.used(begin) );
3048 335 : return suspend(cs.begin(), state::num6, num);
3049 : }
3050 1 : goto finish_int;
3051 : }
3052 1019952 : char const c = *cs;
3053 1019952 : if(BOOST_JSON_LIKELY( c == '.' ))
3054 : {
3055 1009590 : ++cs;
3056 : }
3057 10362 : else if( (c | 32) == 'e' )
3058 : {
3059 6105 : ++cs;
3060 6105 : goto do_exp1;
3061 : }
3062 : else
3063 : {
3064 4257 : goto finish_int;
3065 : }
3066 : }
3067 :
3068 : // DIGIT
3069 : // first significant digit to the right of decimal
3070 1009992 : do_num7:
3071 : {
3072 1009992 : if(BOOST_JSON_UNLIKELY( !cs ))
3073 : {
3074 423 : if(BOOST_JSON_UNLIKELY( more_ ))
3075 : {
3076 420 : if(BOOST_JSON_UNLIKELY(
3077 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3078 41 : return fail(cs.begin());
3079 :
3080 338 : num_buf_.append( begin, cs.used(begin) );
3081 338 : return suspend(cs.begin(), state::num7, num);
3082 : }
3083 : // digit required
3084 : BOOST_STATIC_CONSTEXPR source_location loc
3085 : = BOOST_CURRENT_LOCATION;
3086 3 : return fail(cs.begin(), error::syntax, &loc);
3087 : }
3088 1009569 : char const c = *cs;
3089 1009569 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3090 : {
3091 : // digit required
3092 : BOOST_STATIC_CONSTEXPR source_location loc
3093 : = BOOST_CURRENT_LOCATION;
3094 131 : return fail(cs.begin(), error::syntax, &loc);
3095 : }
3096 : }
3097 :
3098 : // 1*DIGIT
3099 : // significant digits to the right of decimal
3100 1016281 : do_num8:
3101 20507386 : for(;;)
3102 : {
3103 21523667 : if(BOOST_JSON_UNLIKELY( !cs ))
3104 : {
3105 5600 : if(BOOST_JSON_UNLIKELY( more_ ))
3106 : {
3107 4517 : if(BOOST_JSON_UNLIKELY(
3108 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3109 87 : return fail(cs.begin());
3110 :
3111 4343 : num_buf_.append( begin, cs.used(begin) );
3112 4342 : return suspend(cs.begin(), state::num8, num);
3113 : }
3114 1083 : goto finish_dub;
3115 : }
3116 21518067 : char const c = *cs;
3117 21518067 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3118 : {
3119 20507386 : ++cs;
3120 : }
3121 1010681 : else if( (c | 32) == 'e' )
3122 : {
3123 1006180 : ++cs;
3124 1006180 : goto do_exp1;
3125 : }
3126 : else
3127 : {
3128 4501 : goto finish_dub;
3129 : }
3130 : }
3131 :
3132 : // *[+-]
3133 1014276 : do_exp1:
3134 1014276 : if(BOOST_JSON_UNLIKELY( !cs ))
3135 : {
3136 422 : if(BOOST_JSON_UNLIKELY(
3137 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3138 49 : return fail(cs.begin());
3139 :
3140 324 : num_buf_.append( begin, cs.used(begin) );
3141 324 : return maybe_suspend(cs.begin(), state::exp1, num);
3142 : }
3143 1013854 : if( (*cs == '+') || (*cs == '-') )
3144 : {
3145 503310 : ++cs;
3146 : }
3147 :
3148 : // DIGIT
3149 : // first digit of the exponent
3150 510544 : do_exp2:
3151 : {
3152 1013970 : if(BOOST_JSON_UNLIKELY( !cs ))
3153 : {
3154 165 : if(BOOST_JSON_UNLIKELY( more_ ))
3155 : {
3156 156 : if(BOOST_JSON_UNLIKELY(
3157 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3158 20 : return fail(cs.begin());
3159 :
3160 116 : num_buf_.append( begin, cs.used(begin) );
3161 116 : return suspend(cs.begin(), state::exp2, num);
3162 : }
3163 : // digit required
3164 : BOOST_STATIC_CONSTEXPR source_location loc
3165 : = BOOST_CURRENT_LOCATION;
3166 9 : return fail(cs.begin(), error::syntax, &loc);
3167 : }
3168 1013805 : char const c = *cs;
3169 1013805 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3170 : {
3171 : // digit required
3172 : BOOST_STATIC_CONSTEXPR source_location loc
3173 : = BOOST_CURRENT_LOCATION;
3174 268 : return fail(cs.begin(), error::syntax, &loc);
3175 : }
3176 1013537 : ++cs;
3177 : }
3178 :
3179 : // 1*DIGIT
3180 : // subsequent digits in the exponent
3181 1016986 : do_exp3:
3182 2193285 : for(;;)
3183 : {
3184 3210271 : if(BOOST_JSON_UNLIKELY( !cs ))
3185 : {
3186 1005978 : if(BOOST_JSON_UNLIKELY( more_ ))
3187 : {
3188 3621 : if(BOOST_JSON_UNLIKELY(
3189 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3190 86 : return fail(cs.begin());
3191 :
3192 3449 : num_buf_.append( begin, cs.used(begin) );
3193 3449 : return suspend(cs.begin(), state::exp3, num);
3194 : }
3195 : }
3196 : else
3197 : {
3198 2204293 : char const c = *cs;
3199 2204293 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3200 : {
3201 2193285 : ++cs;
3202 2193285 : continue;
3203 : }
3204 : }
3205 1013365 : goto finish_dub;
3206 : }
3207 :
3208 4446 : finish_int:
3209 2843 : if( negative || (!stack_empty && num.neg) )
3210 : {
3211 2047 : if(BOOST_JSON_UNLIKELY(
3212 : !h_.on_int64(
3213 : static_cast<int64_t>(~num.mant + 1),
3214 : {begin, cs.used(begin)},
3215 : ec_) ))
3216 340 : return fail( cs.begin() );
3217 1367 : return cs.begin();
3218 : }
3219 2399 : if(num.mant <= INT64_MAX)
3220 : {
3221 2017 : finish_signed:
3222 2062 : if(BOOST_JSON_UNLIKELY(
3223 : !h_.on_int64(
3224 : static_cast<int64_t>(num.mant),
3225 : {begin, cs.used(begin)},
3226 : ec_) ))
3227 341 : return fail( cs.begin() );
3228 1380 : return cs.begin();
3229 : }
3230 386 : if(BOOST_JSON_UNLIKELY(
3231 : !h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_) ))
3232 64 : return fail( cs.begin() );
3233 258 : return cs.begin();
3234 1020926 : finish_dub:
3235 : double d;
3236 1020926 : std::size_t const size = cs.used(begin);
3237 1020926 : char const* data = begin;
3238 1020926 : std::size_t full_size = size;
3239 : // if we previously suspended or if the current input ends with the
3240 : // number, we need to copy the current part of the number to the
3241 : // temporary buffer
3242 1020926 : if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
3243 : {
3244 8393 : data = num_buf_.append(begin, size);
3245 8393 : full_size = num_buf_.size();
3246 : }
3247 1020926 : auto const err = detail::charconv::from_chars(data, data + full_size, d);
3248 1020926 : BOOST_ASSERT( err.ec != std::errc::invalid_argument );
3249 1020926 : BOOST_ASSERT( err.ptr == data + full_size );
3250 : (void)err;
3251 1020926 : if(BOOST_JSON_UNLIKELY( !h_.on_double(d, {begin, size}, ec_) ))
3252 1871 : return fail( cs.begin() );
3253 1017184 : return cs.begin();
3254 : }
3255 :
3256 : template<class Handler>
3257 : template<bool StackEmpty_, char First_>
3258 : char const*
3259 40497 : basic_parser<Handler>::
3260 : skip_number(
3261 : char const* p,
3262 : std::integral_constant<bool, StackEmpty_> stack_empty,
3263 : std::integral_constant<char, First_> first)
3264 : {
3265 : // only one of these will be true if we are not resuming
3266 : // if negative then !zero_first && !nonzero_first
3267 : // if zero_first then !nonzero_first && !negative
3268 : // if nonzero_first then !zero_first && !negative
3269 40497 : bool const negative = first == '-';
3270 40497 : bool const zero_first = first == '0';
3271 40497 : bool const nonzero_first = first == '+';
3272 40497 : detail::const_stream_wrapper cs(p, end_);
3273 : number num;
3274 40497 : const char* begin = cs.begin();
3275 40497 : if(stack_empty || st_.empty())
3276 : {
3277 28413 : num.neg = negative;
3278 :
3279 : //----------------------------------
3280 : //
3281 : // '-'
3282 : // leading minus sign
3283 : //
3284 28413 : BOOST_ASSERT(cs);
3285 : if(negative)
3286 11798 : ++cs;
3287 :
3288 : // fast path
3289 28413 : if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
3290 : {
3291 : int n1;
3292 :
3293 2433 : if( nonzero_first || (negative && *cs != '0') )
3294 : {
3295 950 : n1 = detail::count_digits( cs.begin() );
3296 950 : BOOST_ASSERT(n1 >= 0 && n1 <= 16);
3297 :
3298 396 : if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
3299 : {
3300 7 : return parse_literal(
3301 : p - 1,
3302 6 : detail::literals_c<detail::literals::neg_infinity>());
3303 : }
3304 :
3305 389 : if( ! nonzero_first && n1 == 0 )
3306 : {
3307 : // digit required
3308 : BOOST_STATIC_CONSTEXPR source_location loc
3309 : = BOOST_CURRENT_LOCATION;
3310 2 : return fail(cs.begin(), error::syntax, &loc);
3311 : }
3312 :
3313 941 : cs += n1;
3314 :
3315 : // integer or floating-point with
3316 : // >= 16 leading digits
3317 941 : if( n1 == 16 )
3318 : {
3319 280 : goto do_num2;
3320 : }
3321 : }
3322 : else
3323 : {
3324 : // 0. floating-point or 0e integer
3325 5295 : n1 = 0;
3326 5295 : ++cs;
3327 : }
3328 :
3329 : {
3330 5956 : char const c = *cs;
3331 5956 : if(c != '.')
3332 : {
3333 1693 : if((c | 32) == 'e')
3334 : {
3335 1644 : ++cs;
3336 1644 : goto do_exp1;
3337 : }
3338 49 : goto finish_int;
3339 : }
3340 : }
3341 :
3342 : // floating-point number
3343 :
3344 4263 : ++cs;
3345 :
3346 4263 : int n2 = detail::count_digits( cs.begin() );
3347 4263 : BOOST_ASSERT(n2 >= 0 && n2 <= 16);
3348 :
3349 4263 : if( n2 == 0 )
3350 : {
3351 : // digit required
3352 : BOOST_STATIC_CONSTEXPR source_location loc
3353 : = BOOST_CURRENT_LOCATION;
3354 3 : return fail(cs.begin(), error::syntax, &loc);
3355 : }
3356 :
3357 : // floating-point mantissa overflow
3358 4260 : if( n1 + n2 >= 19 )
3359 : {
3360 6 : goto do_num7;
3361 : }
3362 :
3363 4254 : cs += n2;
3364 :
3365 4254 : char ch = *cs;
3366 :
3367 4254 : if( (ch | 32) == 'e' )
3368 : {
3369 23 : ++cs;
3370 23 : goto do_exp1;
3371 : }
3372 4231 : else if( ch >= '0' && ch <= '9' )
3373 : {
3374 2501 : goto do_num8;
3375 : }
3376 :
3377 1730 : goto finish_dub;
3378 : }
3379 : }
3380 : else
3381 : {
3382 12084 : num = num_;
3383 : state st;
3384 12084 : st_.pop(st);
3385 12084 : switch(st)
3386 : {
3387 : default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
3388 361 : case state::num1: goto do_num1;
3389 2822 : case state::num2: goto do_num2;
3390 333 : case state::num6: goto do_num6;
3391 338 : case state::num7: goto do_num7;
3392 4341 : case state::num8: goto do_num8;
3393 324 : case state::exp1: goto do_exp1;
3394 116 : case state::exp2: goto do_exp2;
3395 3449 : case state::exp3: goto do_exp3;
3396 : }
3397 : }
3398 :
3399 : // DIGIT first digit
3400 22529 : do_num1:
3401 9726 : if( zero_first || nonzero_first || BOOST_JSON_LIKELY(cs) )
3402 : {
3403 22048 : char const c = *cs;
3404 : if(zero_first)
3405 : {
3406 5529 : ++cs;
3407 5529 : goto do_num6;
3408 : }
3409 9245 : else if( nonzero_first || BOOST_JSON_LIKELY(c >= '1' && c <= '9') )
3410 : {
3411 11163 : ++cs;
3412 : }
3413 5356 : else if(BOOST_JSON_UNLIKELY( c == '0' ))
3414 : {
3415 4309 : ++cs;
3416 4309 : goto do_num6;
3417 : }
3418 1047 : else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
3419 : {
3420 915 : st_.push(state::lit1);
3421 915 : cur_lit_ = literal_index(detail::literals::neg_infinity);
3422 915 : lit_offset_ = 1;
3423 915 : return parse_literal(
3424 869 : cs.begin(), detail::literals_c<detail::literals::resume>() );
3425 : }
3426 : else
3427 : {
3428 : BOOST_STATIC_CONSTEXPR source_location loc
3429 : = BOOST_CURRENT_LOCATION;
3430 132 : return fail(cs.begin(), error::syntax, &loc);
3431 : }
3432 : }
3433 : else
3434 : {
3435 481 : if(BOOST_JSON_UNLIKELY(
3436 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3437 60 : return fail(cs.begin());
3438 361 : return maybe_suspend(cs.begin(), state::num1, num);
3439 : }
3440 :
3441 : // 1*DIGIT
3442 : // significant digits left of decimal
3443 14265 : do_num2:
3444 81369 : for(;;)
3445 : {
3446 95634 : if(BOOST_JSON_UNLIKELY( !cs ))
3447 : {
3448 4061 : if(BOOST_JSON_UNLIKELY( more_ ))
3449 : {
3450 3626 : if(BOOST_JSON_UNLIKELY(
3451 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3452 402 : return fail(cs.begin());
3453 2822 : return suspend(cs.begin(), state::num2, num);
3454 : }
3455 435 : goto finish_int;
3456 : }
3457 91573 : char const c = *cs;
3458 91573 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3459 81369 : ++cs;
3460 : else
3461 10204 : break;
3462 : }
3463 :
3464 : // [.eE]
3465 20375 : do_num6:
3466 : {
3467 20375 : if(BOOST_JSON_UNLIKELY( !cs ))
3468 : {
3469 418 : if(BOOST_JSON_UNLIKELY( more_ ))
3470 : {
3471 417 : if(BOOST_JSON_UNLIKELY(
3472 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3473 42 : return fail(cs.begin());
3474 333 : return suspend(cs.begin(), state::num6, num);
3475 : }
3476 1 : goto finish_int;
3477 : }
3478 19957 : char const c = *cs;
3479 19957 : if(BOOST_JSON_LIKELY( c == '.' ))
3480 : {
3481 9639 : ++cs;
3482 : }
3483 10318 : else if((c | 32) == 'e')
3484 : {
3485 6061 : ++cs;
3486 6061 : goto do_exp1;
3487 : }
3488 : else
3489 : {
3490 4257 : goto finish_int;
3491 : }
3492 : }
3493 :
3494 : // DIGIT
3495 : // first significant digit to the right of decimal
3496 9983 : do_num7:
3497 : {
3498 9983 : if(BOOST_JSON_UNLIKELY( !cs ))
3499 : {
3500 423 : if(BOOST_JSON_UNLIKELY( more_ ))
3501 : {
3502 420 : if(BOOST_JSON_UNLIKELY(
3503 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3504 41 : return fail(cs.begin());
3505 338 : return suspend(cs.begin(), state::num7, num);
3506 : }
3507 : // digit required
3508 : BOOST_STATIC_CONSTEXPR source_location loc
3509 : = BOOST_CURRENT_LOCATION;
3510 3 : return fail(cs.begin(), error::syntax, &loc);
3511 : }
3512 9560 : char const c = *cs;
3513 9560 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3514 : {
3515 : // digit required
3516 : BOOST_STATIC_CONSTEXPR source_location loc
3517 : = BOOST_CURRENT_LOCATION;
3518 131 : return fail(cs.begin(), error::syntax, &loc);
3519 : }
3520 : }
3521 :
3522 : // 1*DIGIT
3523 : // significant digits to the right of decimal
3524 16271 : do_num8:
3525 1107975 : for(;;)
3526 : {
3527 1124246 : if(BOOST_JSON_UNLIKELY( !cs ))
3528 : {
3529 5590 : if(BOOST_JSON_UNLIKELY( more_ ))
3530 : {
3531 4515 : if(BOOST_JSON_UNLIKELY(
3532 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3533 87 : return fail(cs.begin());
3534 4341 : return suspend(cs.begin(), state::num8, num);
3535 : }
3536 1075 : goto finish_dub;
3537 : }
3538 1118656 : char const c = *cs;
3539 1118656 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3540 : {
3541 1107975 : ++cs;
3542 : }
3543 10681 : else if((c | 32) == 'e')
3544 : {
3545 6180 : ++cs;
3546 6180 : goto do_exp1;
3547 : }
3548 : else
3549 : {
3550 4501 : goto finish_dub;
3551 : }
3552 : }
3553 :
3554 : // *[+-]
3555 14232 : do_exp1:
3556 14232 : if(BOOST_JSON_UNLIKELY( !cs ))
3557 : {
3558 422 : if(BOOST_JSON_UNLIKELY(
3559 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3560 49 : return fail(cs.begin());
3561 324 : return maybe_suspend(cs.begin(), state::exp1, num);
3562 : }
3563 13810 : if( (*cs == '+') ||(*cs == '-') )
3564 : {
3565 3783 : ++cs;
3566 : }
3567 :
3568 : // DIGIT
3569 : // first digit of the exponent
3570 10027 : do_exp2:
3571 : {
3572 13926 : if(BOOST_JSON_UNLIKELY( !cs ))
3573 : {
3574 165 : if(BOOST_JSON_UNLIKELY( more_ ))
3575 : {
3576 156 : if(BOOST_JSON_UNLIKELY(
3577 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3578 20 : return fail(cs.begin());
3579 116 : return suspend(cs.begin(), state::exp2, num);
3580 : }
3581 : // digit required
3582 : BOOST_STATIC_CONSTEXPR source_location loc
3583 : = BOOST_CURRENT_LOCATION;
3584 9 : return fail(cs.begin(), error::syntax, &loc);
3585 : }
3586 13761 : char const c = *cs;
3587 13761 : if(BOOST_JSON_UNLIKELY( c < '0' || c > '9' ))
3588 : {
3589 : // digit required
3590 : BOOST_STATIC_CONSTEXPR source_location loc
3591 : = BOOST_CURRENT_LOCATION;
3592 268 : return fail(cs.begin(), error::syntax, &loc);
3593 : }
3594 13493 : ++cs;
3595 : }
3596 :
3597 : // 1*DIGIT
3598 : // subsequent digits in the exponent
3599 16942 : do_exp3:
3600 547187 : for(;;)
3601 : {
3602 564129 : if(BOOST_JSON_UNLIKELY( !cs ))
3603 : {
3604 5934 : if(BOOST_JSON_UNLIKELY( more_ ))
3605 : {
3606 3621 : if(BOOST_JSON_UNLIKELY(
3607 : !h_.on_number_part({begin, cs.used(begin)}, ec_) ))
3608 86 : return fail(cs.begin());
3609 3449 : return suspend(cs.begin(), state::exp3, num);
3610 : }
3611 : }
3612 : else
3613 : {
3614 558195 : char const c = *cs;
3615 558195 : if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
3616 : {
3617 547187 : ++cs;
3618 547187 : continue;
3619 : }
3620 : }
3621 13321 : goto finish_dub;
3622 : }
3623 :
3624 4742 : finish_int:
3625 4742 : if(BOOST_JSON_UNLIKELY( !h_.on_int64(0, {begin, cs.used(begin)}, ec_) ))
3626 770 : return fail( cs.begin() );
3627 3202 : return cs.begin();
3628 20627 : finish_dub:
3629 20627 : std::size_t const size = cs.used(begin);
3630 20627 : if(BOOST_JSON_UNLIKELY( !h_.on_double(0, {begin, size}, ec_) ))
3631 1846 : return fail( cs.begin() );
3632 16935 : return cs.begin();
3633 : }
3634 :
3635 : //----------------------------------------------------------
3636 :
3637 : template<class Handler>
3638 : template<class... Args>
3639 2218617 : basic_parser<Handler>::
3640 : basic_parser(
3641 : parse_options const& opt,
3642 : Args&&... args)
3643 2218608 : : h_(std::forward<Args>(args)...)
3644 2218617 : , opt_(opt)
3645 : {
3646 2218617 : }
3647 :
3648 : //----------------------------------------------------------
3649 :
3650 : template<class Handler>
3651 : void
3652 4154570 : basic_parser<Handler>::
3653 : reset() noexcept
3654 : {
3655 4154570 : ec_ = {};
3656 4154570 : st_.clear();
3657 4154570 : more_ = true;
3658 4154570 : done_ = false;
3659 4154570 : clean_ = true;
3660 4154570 : num_buf_.clear();
3661 4154570 : }
3662 :
3663 : template<class Handler>
3664 : void
3665 18 : basic_parser<Handler>::
3666 : fail(system::error_code ec) noexcept
3667 : {
3668 18 : if(! ec)
3669 : {
3670 : // assign an arbitrary
3671 : // error code to prevent UB
3672 1 : BOOST_JSON_FAIL(ec_, error::incomplete);
3673 : }
3674 : else
3675 : {
3676 17 : ec_ = ec;
3677 : }
3678 18 : done_ = false;
3679 18 : }
3680 :
3681 : //----------------------------------------------------------
3682 :
3683 : template<class Handler>
3684 : std::size_t
3685 10798826 : basic_parser<Handler>::
3686 : write_some(
3687 : bool more,
3688 : char const* data,
3689 : std::size_t size,
3690 : system::error_code& ec)
3691 : {
3692 : // see if we exited via exception
3693 : // on the last call to write_some
3694 10798826 : if(! clean_)
3695 : {
3696 : // prevent UB
3697 1 : if(! ec_)
3698 : {
3699 1 : BOOST_JSON_FAIL(ec_, error::exception);
3700 : }
3701 : }
3702 10798826 : if(ec_)
3703 : {
3704 : // error is sticky
3705 5 : ec = ec_;
3706 5 : return 0;
3707 : }
3708 10798821 : clean_ = false;
3709 10798821 : more_ = more;
3710 10798821 : end_ = data + size;
3711 : const char* p;
3712 10798821 : if(BOOST_JSON_LIKELY(st_.empty()))
3713 : {
3714 : // first time
3715 2218606 : depth_ = opt_.max_depth;
3716 2218606 : if(BOOST_JSON_UNLIKELY(
3717 : ! h_.on_document_begin(ec_)))
3718 : {
3719 14678 : ec = ec_;
3720 14678 : return 0;
3721 : }
3722 2189249 : p = parse_document(data, std::true_type());
3723 : }
3724 : else
3725 : {
3726 8580215 : p = parse_document(data, std::false_type());
3727 : }
3728 :
3729 10743112 : if(BOOST_JSON_LIKELY(p != sentinel()))
3730 : {
3731 2116271 : BOOST_ASSERT(! ec_);
3732 2116271 : if(! done_)
3733 : {
3734 2042494 : done_ = true;
3735 2042494 : h_.on_document_end(ec_);
3736 : }
3737 : }
3738 : else
3739 : {
3740 8626841 : if(! ec_)
3741 : {
3742 8590422 : if(! more_)
3743 : {
3744 591 : BOOST_JSON_FAIL(ec_, error::incomplete);
3745 : }
3746 8589831 : else if(! st_.empty())
3747 : {
3748 : // consume as much trailing whitespace in
3749 : // the JSON document as possible, but still
3750 : // consider the parse complete
3751 : state st;
3752 8589831 : st_.peek(st);
3753 8589831 : if( st == state::doc3 &&
3754 101217 : ! done_)
3755 : {
3756 83390 : done_ = true;
3757 83390 : h_.on_document_end(ec_);
3758 : }
3759 : }
3760 : }
3761 8622045 : p = end_;
3762 : }
3763 10731866 : ec = ec_;
3764 10731866 : clean_ = true;
3765 10731866 : return p - data;
3766 : }
3767 :
3768 : template<class Handler>
3769 : std::size_t
3770 1 : basic_parser<Handler>::
3771 : write_some(
3772 : bool more,
3773 : char const* data,
3774 : std::size_t size,
3775 : std::error_code& ec)
3776 : {
3777 1 : system::error_code jec;
3778 1 : std::size_t const result = write_some(more, data, size, jec);
3779 1 : ec = jec;
3780 1 : return result;
3781 : }
3782 :
3783 : #endif
3784 :
3785 : } // namespace json
3786 : } // namespace boost
3787 :
3788 : #ifdef _MSC_VER
3789 : #pragma warning(pop)
3790 : #endif
3791 :
3792 : #endif
|