File indexing completed on 2025-09-17 08:34:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_JSON_BASIC_PARSER_IMPL_HPP
0012 #define BOOST_JSON_BASIC_PARSER_IMPL_HPP
0013
0014 #include <boost/json/detail/config.hpp>
0015 #include <boost/json/detail/literals.hpp>
0016 #include <boost/json/basic_parser.hpp>
0017 #include <boost/json/error.hpp>
0018 #include <boost/json/detail/buffer.hpp>
0019 #include <boost/json/detail/charconv/from_chars.hpp>
0020 #include <boost/json/detail/sse2.hpp>
0021 #include <boost/mp11/algorithm.hpp>
0022 #include <boost/mp11/integral.hpp>
0023 #include <cmath>
0024 #include <limits>
0025 #include <cstring>
0026
0027 #ifdef _MSC_VER
0028 #pragma warning(push)
0029 #pragma warning(disable: 4702)
0030 #pragma warning(disable: 4127)
0031 #endif
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 #ifndef BOOST_JSON_DOCS
0048
0049 namespace boost {
0050 namespace json {
0051 namespace detail {
0052
0053 inline
0054 double
0055 pow10(int exp) noexcept
0056 {
0057 static double const tab[618] = {
0058 1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
0059
0060 1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
0061 1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
0062 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
0063 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
0064 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
0065 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
0066 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
0067 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
0068 1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
0069 1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
0070
0071 1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
0072 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
0073 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
0074 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
0075 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
0076 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
0077 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
0078 1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
0079 1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
0080 1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
0081
0082 1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
0083 1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
0084 1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
0085 1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
0086 1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
0087 1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
0088 1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
0089 1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
0090 1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
0091 1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
0092
0093 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
0094 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
0095 1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
0096 1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
0097 1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
0098 1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
0099 1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
0100 1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
0101 1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
0102 1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
0103
0104 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
0105 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
0106 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
0107 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
0108 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
0109 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
0110 1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
0111 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
0112 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
0113 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
0114
0115 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
0116 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
0117 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
0118 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
0119 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
0120 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
0121 1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
0122 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
0123 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
0124 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
0125
0126 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
0127
0128 if( exp > 308 )
0129 {
0130 return std::numeric_limits<double>::infinity();
0131 }
0132 else if( exp < -308 )
0133 {
0134
0135
0136 return 0.0;
0137 }
0138 else
0139 {
0140 exp += 308;
0141 BOOST_ASSERT(exp >= 0 && exp < 618);
0142 return tab[exp];
0143 }
0144 }
0145
0146 inline
0147 double
0148 dec_to_float(
0149 std::uint64_t m,
0150 std::int32_t e,
0151 bool neg) noexcept
0152 {
0153
0154 double x = static_cast<double>(m);
0155 if(neg)
0156 x = -x;
0157
0158 if(e < -305)
0159 {
0160 x *= 1e-305 ;
0161 e += 305;
0162 }
0163
0164 if(e >= -22 && e < 0)
0165 return x / pow10(-e);
0166
0167 return x * pow10(e);
0168 }
0169
0170 inline
0171 bool
0172 is_control(char c) noexcept
0173 {
0174 return static_cast<unsigned char>(c) < 32;
0175 }
0176
0177 inline
0178 int
0179 hex_digit(unsigned char c) noexcept
0180 {
0181
0182 if( c >= '0' && c <= '9' )
0183 return c - '0';
0184 c &= ~0x20;
0185 if( c >= 'A' && c <= 'F' )
0186 return 10 + c - 'A';
0187 return -1;
0188 }
0189
0190 }
0191
0192
0193
0194 template< class Handler >
0195 template< bool StackEmpty_, char First_ >
0196 struct basic_parser<Handler>::
0197 parse_number_helper
0198 {
0199 basic_parser* parser;
0200 char const* p;
0201
0202 template< std::size_t N >
0203 char const*
0204 operator()( mp11::mp_size_t<N> ) const
0205 {
0206 return parser->parse_number(
0207 p,
0208 std::integral_constant<bool, StackEmpty_>(),
0209 std::integral_constant<char, First_>(),
0210 std::integral_constant<
0211 number_precision, static_cast<number_precision>(N)>() );
0212 }
0213 };
0214
0215
0216
0217 template<class Handler>
0218 void
0219 basic_parser<Handler>::
0220 reserve()
0221 {
0222 if(BOOST_JSON_LIKELY(
0223 ! st_.empty()))
0224 return;
0225
0226
0227 st_.reserve(
0228 sizeof(state) +
0229 (sizeof(state) +
0230 sizeof(std::size_t)) * depth() +
0231 sizeof(state) +
0232 sizeof(std::size_t) +
0233 sizeof(state));
0234 }
0235
0236
0237
0238
0239
0240
0241
0242
0243 template<class Handler>
0244 const char*
0245 basic_parser<Handler>::
0246 sentinel()
0247 {
0248
0249
0250 return reinterpret_cast<
0251 const char*>(this) + 1;
0252 }
0253
0254 template<class Handler>
0255 bool
0256 basic_parser<Handler>::
0257 incomplete(
0258 const detail::const_stream_wrapper& cs)
0259 {
0260 return cs.begin() == sentinel();
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270 template<class Handler>
0271 const char*
0272 basic_parser<Handler>::
0273 suspend_or_fail(state st)
0274 {
0275 if(BOOST_JSON_LIKELY(
0276 ! ec_ && more_))
0277 {
0278
0279 reserve();
0280 st_.push_unchecked(st);
0281 }
0282 return sentinel();
0283 }
0284
0285 template<class Handler>
0286 const char*
0287 basic_parser<Handler>::
0288 suspend_or_fail(
0289 state st,
0290 std::size_t n)
0291 {
0292 if(BOOST_JSON_LIKELY(
0293 ! ec_ && more_))
0294 {
0295
0296 reserve();
0297 st_.push_unchecked(n);
0298 st_.push_unchecked(st);
0299 }
0300 return sentinel();
0301 }
0302
0303
0304 template<class Handler>
0305 const char*
0306 basic_parser<Handler>::
0307 fail(const char* p) noexcept
0308 {
0309 BOOST_ASSERT( p != sentinel() );
0310 end_ = p;
0311 return sentinel();
0312 }
0313
0314 template<class Handler>
0315 const char*
0316 basic_parser<Handler>::
0317 fail(
0318 const char* p,
0319 error ev,
0320 source_location const* loc) noexcept
0321 {
0322 BOOST_ASSERT( p != sentinel() );
0323 end_ = p;
0324 ec_.assign(ev, loc);
0325 return sentinel();
0326 }
0327
0328 template<class Handler>
0329 const char*
0330 basic_parser<Handler>::
0331 maybe_suspend(
0332 const char* p,
0333 state st)
0334 {
0335 if( p != sentinel() )
0336 end_ = p;
0337 if(BOOST_JSON_LIKELY(more_))
0338 {
0339
0340 reserve();
0341 st_.push_unchecked(st);
0342 }
0343 return sentinel();
0344 }
0345
0346 template<class Handler>
0347 const char*
0348 basic_parser<Handler>::
0349 maybe_suspend(
0350 const char* p,
0351 state st,
0352 std::size_t n)
0353 {
0354 BOOST_ASSERT( p != sentinel() );
0355 end_ = p;
0356 if(BOOST_JSON_LIKELY(more_))
0357 {
0358
0359 reserve();
0360 st_.push_unchecked(n);
0361 st_.push_unchecked(st);
0362 }
0363 return sentinel();
0364 }
0365
0366 template<class Handler>
0367 const char*
0368 basic_parser<Handler>::
0369 maybe_suspend(
0370 const char* p,
0371 state st,
0372 const number& num)
0373 {
0374 BOOST_ASSERT( p != sentinel() );
0375 end_ = p;
0376 if(BOOST_JSON_LIKELY(more_))
0377 {
0378
0379 num_ = num;
0380 reserve();
0381 st_.push_unchecked(st);;
0382 }
0383 return sentinel();
0384 }
0385
0386 template<class Handler>
0387 const char*
0388 basic_parser<Handler>::
0389 suspend(
0390 const char* p,
0391 state st)
0392 {
0393 BOOST_ASSERT( p != sentinel() );
0394 end_ = p;
0395
0396 reserve();
0397 st_.push_unchecked(st);
0398 return sentinel();
0399 }
0400
0401 template<class Handler>
0402 const char*
0403 basic_parser<Handler>::
0404 suspend(
0405 const char* p,
0406 state st,
0407 const number& num)
0408 {
0409 BOOST_ASSERT( p != sentinel() );
0410 end_ = p;
0411
0412 num_ = num;
0413 reserve();
0414 st_.push_unchecked(st);
0415 return sentinel();
0416 }
0417
0418 template<class Handler>
0419 template<
0420 bool StackEmpty_
0421 >
0422 const char*
0423 basic_parser<Handler>::
0424 parse_comment(const char* p,
0425 std::integral_constant<bool, StackEmpty_> stack_empty,
0426 bool terminal)
0427 {
0428 detail::const_stream_wrapper cs(p, end_);
0429 const char* start = cs.begin();
0430 std::size_t remain;
0431 if(! stack_empty && ! st_.empty())
0432 {
0433 state st;
0434 st_.pop(st);
0435 switch(st)
0436 {
0437 default: BOOST_JSON_UNREACHABLE();
0438 case state::com1: goto do_com1;
0439 case state::com2: goto do_com2;
0440 case state::com3: goto do_com3;
0441 case state::com4: goto do_com4;
0442 }
0443 }
0444 BOOST_ASSERT(*cs == '/');
0445 ++cs;
0446 do_com1:
0447 if(BOOST_JSON_UNLIKELY(! cs))
0448 return maybe_suspend(cs.begin(), state::com1);
0449 switch(*cs)
0450 {
0451 default:
0452 {
0453 BOOST_STATIC_CONSTEXPR source_location loc
0454 = BOOST_CURRENT_LOCATION;
0455 return fail(cs.begin(), error::syntax, &loc);
0456 }
0457 case '/':
0458 ++cs;
0459 do_com2:
0460
0461 remain = cs.remain();
0462 cs = remain ? static_cast<const char*>(
0463 std::memchr(cs.begin(), '\n', remain)) : sentinel();
0464 if(! cs.begin())
0465 cs = sentinel();
0466 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
0467 {
0468
0469
0470
0471 if(terminal && ! more_)
0472 {
0473 if(BOOST_JSON_UNLIKELY(! h_.on_comment(
0474 {start, cs.remain(start)}, ec_)))
0475 return fail(cs.end());
0476 return cs.end();
0477 }
0478 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
0479 {start, cs.remain(start)}, ec_)))
0480 return fail(cs.end());
0481 if(terminal)
0482 return suspend(cs.end(), state::com2);
0483 return maybe_suspend(cs.end(), state::com2);
0484 }
0485 break;
0486 case '*':
0487 do
0488 {
0489 ++cs;
0490 do_com3:
0491
0492 remain = cs.remain();
0493 cs = remain ? static_cast<const char*>(
0494 std::memchr(cs.begin(), '*', remain)) : sentinel();
0495 if(! cs.begin())
0496 cs = sentinel();
0497
0498 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
0499 {
0500 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
0501 {start, cs.remain(start)}, ec_)))
0502 return fail(cs.end());
0503 return maybe_suspend(cs.end(), state::com3);
0504 }
0505
0506 ++cs;
0507 do_com4:
0508 if(BOOST_JSON_UNLIKELY(! cs))
0509 {
0510 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
0511 {start, cs.used(start)}, ec_)))
0512 return fail(cs.begin());
0513 return maybe_suspend(cs.begin(), state::com4);
0514 }
0515 }
0516 while(*cs != '/');
0517 }
0518 ++cs;
0519 if(BOOST_JSON_UNLIKELY(! h_.on_comment(
0520 {start, cs.used(start)}, ec_)))
0521 return fail(cs.begin());
0522 return cs.begin();
0523 }
0524
0525 template<class Handler>
0526 template<bool StackEmpty_>
0527 const char*
0528 basic_parser<Handler>::
0529 parse_document(const char* p,
0530 std::integral_constant<bool, StackEmpty_> stack_empty)
0531 {
0532 detail::const_stream_wrapper cs(p, end_);
0533 if(! stack_empty && ! st_.empty())
0534 {
0535 state st;
0536 st_.peek(st);
0537 switch(st)
0538 {
0539 default: goto do_doc2;
0540 case state::doc1:
0541 st_.pop(st);
0542 goto do_doc1;
0543 case state::doc3:
0544 st_.pop(st);
0545 goto do_doc3;
0546 case state::com1: case state::com2:
0547 case state::com3: case state::com4:
0548 goto do_doc4;
0549 }
0550 }
0551 do_doc1:
0552 cs = detail::count_whitespace(cs.begin(), cs.end());
0553 if(BOOST_JSON_UNLIKELY(! cs))
0554 return maybe_suspend(cs.begin(), state::doc1);
0555 do_doc2:
0556 switch(+opt_.allow_comments |
0557 (opt_.allow_trailing_commas << 1) |
0558 (opt_.allow_invalid_utf8 << 2))
0559 {
0560
0561 default:
0562 cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
0563 break;
0564
0565 case 1:
0566 cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
0567 break;
0568
0569 case 2:
0570 cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
0571 break;
0572
0573 case 3:
0574 cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
0575 break;
0576
0577 case 4:
0578 cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
0579 break;
0580
0581 case 5:
0582 cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
0583 break;
0584
0585 case 6:
0586 cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
0587 break;
0588
0589 case 7:
0590 cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
0591 break;
0592 }
0593 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
0594
0595 return sentinel();
0596 do_doc3:
0597 cs = detail::count_whitespace(cs.begin(), cs.end());
0598 if(BOOST_JSON_UNLIKELY(! cs))
0599 {
0600 if(more_)
0601 return suspend(cs.begin(), state::doc3);
0602 }
0603 else if(opt_.allow_comments && *cs == '/')
0604 {
0605 do_doc4:
0606 cs = parse_comment(cs.begin(), stack_empty, std::true_type());
0607 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
0608 return sentinel();
0609 goto do_doc3;
0610 }
0611 return cs.begin();
0612 }
0613
0614 template<class Handler>
0615 template<
0616 bool StackEmpty_,
0617 bool AllowComments_
0618
0619 >
0620 const char*
0621 basic_parser<Handler>::
0622 parse_value(const char* p,
0623 std::integral_constant<bool, StackEmpty_> stack_empty,
0624 std::integral_constant<bool, AllowComments_> allow_comments,
0625 bool allow_trailing,
0626 bool allow_bad_utf8,
0627 bool allow_bad_utf16)
0628 {
0629 if(stack_empty || st_.empty())
0630 {
0631 loop:
0632 switch(*p)
0633 {
0634 case '0':
0635 return mp11::mp_with_index<3>(
0636 static_cast<unsigned char>(opt_.numbers),
0637 parse_number_helper<true, '0'>{ this, p });
0638 case '-':
0639 return mp11::mp_with_index<3>(
0640 static_cast<unsigned char>(opt_.numbers),
0641 parse_number_helper<true, '-'>{ this, p });
0642 case '1': case '2': case '3':
0643 case '4': case '5': case '6':
0644 case '7': case '8': case '9':
0645 return mp11::mp_with_index<3>(
0646 static_cast<unsigned char>(opt_.numbers),
0647 parse_number_helper<true, '+'>{ this, p });
0648 case 'n':
0649 return parse_literal( p, detail::literals_c<detail::literals::null>() );
0650 case 't':
0651 return parse_literal( p, detail::literals_c<detail::literals::true_>() );
0652 case 'f':
0653 return parse_literal( p, detail::literals_c<detail::literals::false_>() );
0654 case 'I':
0655 if( !opt_.allow_infinity_and_nan )
0656 {
0657 BOOST_STATIC_CONSTEXPR source_location loc
0658 = BOOST_CURRENT_LOCATION;
0659 return fail(p, error::syntax, &loc);
0660 }
0661 return parse_literal( p, detail::literals_c<detail::literals::infinity>() );
0662 case 'N':
0663 if( !opt_.allow_infinity_and_nan )
0664 {
0665 BOOST_STATIC_CONSTEXPR source_location loc
0666 = BOOST_CURRENT_LOCATION;
0667 return fail(p, error::syntax, &loc);
0668 }
0669 return parse_literal(p, detail::literals_c<detail::literals::nan>() );
0670 case '"':
0671 return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
0672 case '[':
0673 return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0674 case '{':
0675 return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0676 case '/':
0677 if(! allow_comments)
0678 {
0679 BOOST_STATIC_CONSTEXPR source_location loc
0680 = BOOST_CURRENT_LOCATION;
0681 return fail(p, error::syntax, &loc);
0682 }
0683 p = parse_comment(p, stack_empty, std::false_type());
0684
0685
0686
0687 if(BOOST_JSON_UNLIKELY(p == sentinel()))
0688 return maybe_suspend(p, state::val2);
0689 BOOST_FALLTHROUGH;
0690 case ' ':
0691 case '\t':
0692 case '\n':
0693 case '\r':
0694 p = detail::count_whitespace(p, end_);
0695 if(BOOST_JSON_UNLIKELY(p == end_))
0696 return maybe_suspend(p, state::val1);
0697 goto loop;
0698 default:
0699 {
0700 BOOST_STATIC_CONSTEXPR source_location loc
0701 = BOOST_CURRENT_LOCATION;
0702 return fail(p, error::syntax, &loc);
0703 }
0704 }
0705 }
0706 return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0707 }
0708
0709 template<class Handler>
0710 template<
0711 bool AllowComments_
0712
0713 >
0714 const char*
0715 basic_parser<Handler>::
0716 resume_value(const char* p,
0717 std::integral_constant<bool, AllowComments_> allow_comments,
0718 bool allow_trailing,
0719 bool allow_bad_utf8,
0720 bool allow_bad_utf16)
0721 {
0722 state st;
0723 st_.peek(st);
0724 switch(st)
0725 {
0726 default: BOOST_JSON_UNREACHABLE();
0727 case state::lit1:
0728 return parse_literal(p, detail::literals_c<detail::literals::resume>() );
0729
0730 case state::str1: case state::str2:
0731 case state::str8:
0732 return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
0733
0734 case state::arr1: case state::arr2:
0735 case state::arr3: case state::arr4:
0736 case state::arr5: case state::arr6:
0737 return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0738
0739 case state::obj1: case state::obj2:
0740 case state::obj3: case state::obj4:
0741 case state::obj5: case state::obj6:
0742 case state::obj7: case state::obj8:
0743 case state::obj9: case state::obj10:
0744 case state::obj11:
0745 return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0746
0747 case state::num1: case state::num2:
0748 case state::num3: case state::num4:
0749 case state::num5: case state::num6:
0750 case state::num7: case state::num8:
0751 case state::exp1: case state::exp2:
0752 case state::exp3:
0753 return mp11::mp_with_index<3>(
0754 static_cast<unsigned char>(opt_.numbers),
0755 parse_number_helper<false, 0>{ this, p });
0756
0757
0758 case state::val1:
0759 {
0760 st_.pop(st);
0761 BOOST_ASSERT(st_.empty());
0762 p = detail::count_whitespace(p, end_);
0763 if(BOOST_JSON_UNLIKELY(p == end_))
0764 return maybe_suspend(p, state::val1);
0765 return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
0766 }
0767
0768 case state::val2:
0769 {
0770 st_.pop(st);
0771 p = parse_comment(p, std::false_type(), std::false_type());
0772 if(BOOST_JSON_UNLIKELY(p == sentinel()))
0773 return maybe_suspend(p, state::val2);
0774 if(BOOST_JSON_UNLIKELY( p == end_ ))
0775 return maybe_suspend(p, state::val3);
0776 BOOST_ASSERT(st_.empty());
0777 return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
0778 }
0779
0780 case state::val3:
0781 {
0782 st_.pop(st);
0783 return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
0784 }
0785 }
0786 }
0787
0788 template<class Handler>
0789 template<class Literal>
0790 const char*
0791 basic_parser<Handler>::
0792 parse_literal(const char* p, Literal)
0793 {
0794 using L = detail::literals;
0795
0796 std::size_t cur_lit;
0797 std::size_t offset;
0798
0799 detail::const_stream_wrapper cs(p, end_);
0800 BOOST_IF_CONSTEXPR( Literal::value != L::resume )
0801 {
0802 constexpr std::size_t index = literal_index(Literal::value);
0803 constexpr char const* literal = detail::literal_strings[index];
0804 constexpr std::size_t sz = detail::literal_sizes[index];
0805
0806 if(BOOST_JSON_LIKELY( cs.remain() >= sz ))
0807 {
0808 int const cmp = std::memcmp(cs.begin(), literal, sz);
0809 if( cmp != 0 )
0810 {
0811 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0812 return fail(cs.begin(), error::syntax, &loc);
0813 }
0814
0815 BOOST_IF_CONSTEXPR( Literal::value == L::null )
0816 {
0817 if(BOOST_JSON_UNLIKELY(
0818 ! h_.on_null(ec_)))
0819 return fail(cs.begin());
0820 }
0821 else BOOST_IF_CONSTEXPR( Literal::value == L::true_ )
0822 {
0823 if(BOOST_JSON_UNLIKELY(
0824 ! h_.on_bool(true, ec_)))
0825 return fail(cs.begin());
0826 }
0827 else BOOST_IF_CONSTEXPR( Literal::value == L::false_ )
0828 {
0829 if(BOOST_JSON_UNLIKELY(
0830 ! h_.on_bool(false, ec_)))
0831 return fail(cs.begin());
0832 }
0833 else BOOST_IF_CONSTEXPR( Literal::value == L::infinity )
0834 {
0835 if(BOOST_JSON_UNLIKELY(
0836 ! h_.on_double(
0837 std::numeric_limits<double>::infinity(),
0838 string_view(literal, sz),
0839 ec_)))
0840 return fail(cs.begin());
0841 }
0842 else BOOST_IF_CONSTEXPR( Literal::value == L::neg_infinity )
0843 {
0844 if(BOOST_JSON_UNLIKELY(
0845 ! h_.on_double(
0846 -std::numeric_limits<double>::infinity(),
0847 string_view(literal, sz),
0848 ec_)))
0849 return fail(cs.begin());
0850 }
0851 else BOOST_IF_CONSTEXPR( Literal::value == L::nan )
0852 {
0853 if(BOOST_JSON_UNLIKELY(
0854 ! h_.on_double(
0855 std::numeric_limits<double>::quiet_NaN(),
0856 string_view(literal, sz),
0857 ec_)))
0858 return fail(cs.begin());
0859 }
0860 else
0861 {
0862 BOOST_JSON_UNREACHABLE();
0863 }
0864
0865 cs += sz;
0866 return cs.begin();
0867 }
0868
0869 offset = 0;
0870 cur_lit = index;
0871 }
0872 else
0873 {
0874 state st;
0875 st_.pop(st);
0876 BOOST_ASSERT( st == state::lit1 );
0877
0878 cur_lit = cur_lit_;
0879 offset = lit_offset_;
0880 }
0881
0882 std::size_t const lit_size = detail::literal_sizes[cur_lit];
0883 std::size_t const size = (std::min)( lit_size - offset, cs.remain() );
0884 int cmp = 0;
0885 if(BOOST_JSON_LIKELY( cs.begin() ))
0886 cmp = std::memcmp(
0887 cs.begin(), detail::literal_strings[cur_lit] + offset, size );
0888 if( cmp != 0 )
0889 {
0890 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0891 return fail(cs.begin(), error::syntax, &loc);
0892 }
0893
0894 if(BOOST_JSON_UNLIKELY( offset + size < lit_size ))
0895 {
0896 BOOST_ASSERT( cur_lit < 256 );
0897 cur_lit_ = static_cast<unsigned char>( cur_lit );
0898 BOOST_ASSERT( offset + size < 256 );
0899 lit_offset_ = static_cast<unsigned char>( offset + size );
0900 return maybe_suspend(cs.begin() + size, state::lit1);
0901 }
0902
0903 switch( static_cast<L>(cur_lit) )
0904 {
0905 case L::null:
0906 if(BOOST_JSON_UNLIKELY(
0907 ! h_.on_null(ec_)))
0908 return fail(cs.begin());
0909 break;
0910 case L::true_:
0911 if(BOOST_JSON_UNLIKELY(
0912 ! h_.on_bool(true, ec_)))
0913 return fail(cs.begin());
0914 break;
0915 case L::false_:
0916 if(BOOST_JSON_UNLIKELY(
0917 ! h_.on_bool(false, ec_)))
0918 return fail(cs.begin());
0919 break;
0920 case L::infinity:
0921 if(BOOST_JSON_UNLIKELY(
0922 ! h_.on_double(
0923 std::numeric_limits<double>::infinity(),
0924 string_view(
0925 detail::literal_strings[ literal_index(L::infinity) ],
0926 detail::literal_sizes[ literal_index(L::infinity) ]),
0927 ec_)))
0928 return fail(cs.begin());
0929 break;
0930 case L::neg_infinity:
0931 if(BOOST_JSON_UNLIKELY(
0932 ! h_.on_double(
0933 -std::numeric_limits<double>::infinity(),
0934 string_view(
0935 detail::literal_strings[ literal_index(L::neg_infinity) ],
0936 detail::literal_sizes[ literal_index(L::neg_infinity) ]),
0937 ec_)))
0938 return fail(cs.begin());
0939 break;
0940 case L::nan:
0941 if(BOOST_JSON_UNLIKELY(
0942 ! h_.on_double(
0943 std::numeric_limits<double>::quiet_NaN(),
0944 string_view(
0945 detail::literal_strings[ literal_index(L::nan) ],
0946 detail::literal_sizes[ literal_index(L::nan) ]),
0947 ec_)))
0948 return fail(cs.begin());
0949 break;
0950 default: BOOST_JSON_UNREACHABLE();
0951 }
0952
0953 cs += size;
0954 return cs.begin();
0955 }
0956
0957
0958
0959 template<class Handler>
0960 template<bool StackEmpty_, bool IsKey_>
0961 const char*
0962 basic_parser<Handler>::
0963 parse_string(const char* p,
0964 std::integral_constant<bool, StackEmpty_> stack_empty,
0965 std::integral_constant<bool, IsKey_> is_key,
0966 bool allow_bad_utf8,
0967 bool allow_bad_utf16)
0968 {
0969 detail::const_stream_wrapper cs(p, end_);
0970 std::size_t total;
0971 char const* start;
0972 std::size_t size;
0973 if(! stack_empty && ! st_.empty())
0974 {
0975 state st;
0976 st_.pop(st);
0977 st_.pop(total);
0978 switch(st)
0979 {
0980 default: BOOST_JSON_UNREACHABLE();
0981 case state::str2: goto do_str2;
0982 case state::str8: goto do_str8;
0983 case state::str1: break;
0984 }
0985 }
0986 else
0987 {
0988 BOOST_ASSERT(*cs == '\x22');
0989 ++cs;
0990 total = 0;
0991 }
0992
0993 do_str1:
0994 start = cs.begin();
0995 cs = allow_bad_utf8?
0996 detail::count_valid<true>(cs.begin(), cs.end()):
0997 detail::count_valid<false>(cs.begin(), cs.end());
0998 size = cs.used(start);
0999 if(is_key)
1000 {
1001 BOOST_ASSERT(total <= Handler::max_key_size);
1002 if(BOOST_JSON_UNLIKELY(size >
1003 Handler::max_key_size - total))
1004 {
1005 BOOST_STATIC_CONSTEXPR source_location loc
1006 = BOOST_CURRENT_LOCATION;
1007 return fail(cs.begin(), error::key_too_large, &loc);
1008 }
1009 }
1010 else
1011 {
1012 BOOST_ASSERT(total <= Handler::max_string_size);
1013 if(BOOST_JSON_UNLIKELY(size >
1014 Handler::max_string_size - total))
1015 {
1016 BOOST_STATIC_CONSTEXPR source_location loc
1017 = BOOST_CURRENT_LOCATION;
1018 return fail(cs.begin(), error::string_too_large, &loc);
1019 }
1020 }
1021 total += size;
1022 if(BOOST_JSON_UNLIKELY(! cs))
1023 {
1024
1025 if(BOOST_JSON_LIKELY(size))
1026 {
1027 {
1028 bool r = is_key?
1029 h_.on_key_part( {start, size}, total, ec_ ):
1030 h_.on_string_part( {start, size}, total, ec_ );
1031
1032 if(BOOST_JSON_UNLIKELY(!r))
1033 {
1034 return fail(cs.begin());
1035 }
1036 }
1037 }
1038 return maybe_suspend(cs.begin(), state::str1, total);
1039 }
1040
1041
1042
1043 if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
1044 {
1045
1046 if((*cs & 0x80) && !allow_bad_utf8)
1047 {
1048 seq_.save(cs.begin(), cs.remain());
1049 if(BOOST_JSON_UNLIKELY(seq_.complete()))
1050 {
1051 BOOST_STATIC_CONSTEXPR source_location loc
1052 = BOOST_CURRENT_LOCATION;
1053 return fail(cs.begin(), error::syntax, &loc);
1054 }
1055 if(BOOST_JSON_LIKELY(size))
1056 {
1057 bool const r = is_key?
1058 h_.on_key_part( {start, size}, total, ec_ ):
1059 h_.on_string_part( {start, size}, total, ec_ );
1060 if(BOOST_JSON_UNLIKELY( !r ))
1061 return fail( cs.begin() );
1062 }
1063 return maybe_suspend(cs.end(), state::str8, total);
1064 }
1065 else if(BOOST_JSON_LIKELY(*cs == '\\'))
1066 {
1067
1068 if(BOOST_JSON_LIKELY(size))
1069 {
1070 bool const r = is_key?
1071 h_.on_key_part( {start, size}, total, ec_ ):
1072 h_.on_string_part( {start, size}, total, ec_ );
1073 if(BOOST_JSON_UNLIKELY( !r ))
1074 return fail( cs.begin() );
1075 }
1076 do_str2:
1077 cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
1078 if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
1079 return suspend_or_fail(state::str2, total);
1080
1081 goto do_str1;
1082 }
1083
1084 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1085 return fail(cs.begin(), error::syntax, &loc);
1086 }
1087
1088 {
1089 bool r = is_key?
1090 h_.on_key( {start, size}, total, ec_ ):
1091 h_.on_string( {start, size}, total, ec_ );
1092
1093 if(BOOST_JSON_UNLIKELY(!r))
1094 {
1095 return fail(cs.begin());
1096 }
1097 }
1098
1099 ++cs;
1100 return cs.begin();
1101
1102 do_str8:
1103 uint8_t needed = seq_.needed();
1104 if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
1105 return maybe_suspend(cs.end(), state::str8, total);
1106 if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
1107 {
1108 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1109 return fail(cs.begin(), error::syntax, &loc);
1110 }
1111 {
1112 bool const r = is_key?
1113 h_.on_key_part( {seq_.data(), seq_.length()}, total, ec_ ):
1114 h_.on_string_part( {seq_.data(), seq_.length()}, total, ec_ );
1115 if(BOOST_JSON_UNLIKELY( !r ))
1116 return fail( cs.begin() );
1117 }
1118 cs += needed;
1119 goto do_str1;
1120 }
1121
1122 template<class Handler>
1123 template<bool StackEmpty_>
1124 const char*
1125 basic_parser<Handler>::
1126 parse_escaped(
1127 const char* p,
1128 std::size_t& total,
1129 std::integral_constant<bool, StackEmpty_> stack_empty,
1130 bool is_key,
1131 bool allow_bad_utf16)
1132 {
1133 constexpr unsigned urc = 0xFFFD;
1134 auto const ev_too_large = is_key?
1135 error::key_too_large : error::string_too_large;
1136 auto const max_size = is_key?
1137 Handler::max_key_size : Handler::max_string_size;
1138 int digit;
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153 detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
1154
1155
1156
1157
1158
1159
1160 detail::clipped_const_stream cs(p, end_);
1161 cs.clip(temp.max_size());
1162
1163 if(! stack_empty && ! st_.empty())
1164 {
1165 state st;
1166 st_.pop(st);
1167 switch(st)
1168 {
1169 default: BOOST_JSON_UNREACHABLE();
1170 case state::str3: goto do_str3;
1171 case state::str4: goto do_str4;
1172 case state::str5: goto do_str5;
1173 case state::str6: goto do_str6;
1174 case state::str7: goto do_str7;
1175 case state::sur1: goto do_sur1;
1176 case state::sur2: goto do_sur2;
1177 case state::sur3: goto do_sur3;
1178 case state::sur4: goto do_sur4;
1179 case state::sur5: goto do_sur5;
1180 case state::sur6: goto do_sur6;
1181 }
1182 }
1183
1184 while(true)
1185 {
1186 BOOST_ASSERT( temp.capacity() );
1187 BOOST_ASSERT(*cs == '\\');
1188 ++cs;
1189 do_str3:
1190 if(BOOST_JSON_UNLIKELY(! cs))
1191 {
1192 if(BOOST_JSON_LIKELY(! temp.empty()))
1193 {
1194 BOOST_ASSERT(total <= max_size);
1195 if(BOOST_JSON_UNLIKELY(
1196 temp.size() > max_size - total))
1197 {
1198 BOOST_STATIC_CONSTEXPR source_location loc
1199 = BOOST_CURRENT_LOCATION;
1200 return fail(cs.begin(), ev_too_large, &loc);
1201 }
1202 total += temp.size();
1203 {
1204 bool r = is_key
1205 ? h_.on_key_part(temp.get(), total, ec_)
1206 : h_.on_string_part(temp.get(), total, ec_);
1207
1208 if(BOOST_JSON_UNLIKELY(!r))
1209 {
1210 return fail(cs.begin());
1211 }
1212 }
1213 temp.clear();
1214 }
1215 cs.clip(temp.max_size());
1216 if(BOOST_JSON_UNLIKELY(! cs))
1217 return maybe_suspend(cs.begin(), state::str3);
1218 }
1219 switch(*cs)
1220 {
1221 default:
1222 {
1223 BOOST_STATIC_CONSTEXPR source_location loc
1224 = BOOST_CURRENT_LOCATION;
1225 return fail(cs.begin(), error::syntax, &loc);
1226 }
1227 case '\x22':
1228 temp.push_back('\x22');
1229 ++cs;
1230 break;
1231 case '\\':
1232 temp.push_back('\\');
1233 ++cs;
1234 break;
1235 case '/':
1236 temp.push_back('/');
1237 ++cs;
1238 break;
1239 case 'b':
1240 temp.push_back('\x08');
1241 ++cs;
1242 break;
1243 case 'f':
1244 temp.push_back('\x0c');
1245 ++cs;
1246 break;
1247 case 'n':
1248 temp.push_back('\x0a');
1249 ++cs;
1250 break;
1251 case 'r':
1252 temp.push_back('\x0d');
1253 ++cs;
1254 break;
1255 case 't':
1256 temp.push_back('\x09');
1257 ++cs;
1258 break;
1259 case 'u':
1260
1261
1262
1263
1264 if(BOOST_JSON_LIKELY(cs.remain() > 10))
1265 {
1266
1267
1268 digit = detail::load_little_endian<4>(
1269 cs.begin() + 1);
1270 int d4 = detail::hex_digit(static_cast<
1271 unsigned char>(digit >> 24));
1272 int d3 = detail::hex_digit(static_cast<
1273 unsigned char>(digit >> 16));
1274 int d2 = detail::hex_digit(static_cast<
1275 unsigned char>(digit >> 8));
1276 int d1 = detail::hex_digit(static_cast<
1277 unsigned char>(digit));
1278 if(BOOST_JSON_UNLIKELY(
1279 (d1 | d2 | d3 | d4) == -1))
1280 {
1281 if(d1 != -1)
1282 ++cs;
1283 if(d2 != -1)
1284 ++cs;
1285 if(d3 != -1)
1286 ++cs;
1287 BOOST_STATIC_CONSTEXPR source_location loc
1288 = BOOST_CURRENT_LOCATION;
1289 return fail(cs.begin(), error::expected_hex_digit, &loc);
1290 }
1291
1292 unsigned u1 =
1293 (d1 << 12) + (d2 << 8) +
1294 (d3 << 4) + d4;
1295
1296
1297
1298
1299 if(BOOST_JSON_LIKELY(
1300 u1 < 0xd800 || u1 > 0xdfff))
1301 {
1302 cs += 5;
1303 temp.append_utf8(u1);
1304 break;
1305 }
1306 if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
1307 {
1308
1309
1310 if(!allow_bad_utf16)
1311 {
1312 BOOST_STATIC_CONSTEXPR source_location loc
1313 = BOOST_CURRENT_LOCATION;
1314 return fail(cs.begin(), error::illegal_leading_surrogate,
1315 &loc);
1316 }
1317
1318 else
1319 {
1320 cs += 5;
1321 temp.append_utf8(urc);
1322 break;
1323 }
1324 }
1325 cs += 5;
1326
1327
1328
1329 if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1330 {
1331
1332
1333 if(!allow_bad_utf16)
1334 {
1335 BOOST_STATIC_CONSTEXPR source_location loc
1336 = BOOST_CURRENT_LOCATION;
1337 return fail(cs.begin(), error::syntax, &loc);
1338 }
1339
1340
1341 else
1342 {
1343 temp.append_utf8(urc);
1344 break;
1345 }
1346 }
1347 ++cs;
1348 if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1349 {
1350 if (!allow_bad_utf16)
1351 {
1352 BOOST_STATIC_CONSTEXPR source_location loc
1353 = BOOST_CURRENT_LOCATION;
1354 return fail(cs.begin(), error::syntax, &loc);
1355 }
1356
1357
1358 else
1359 {
1360 temp.append_utf8(urc);
1361 goto do_str3;
1362 }
1363 }
1364 ++cs;
1365 digit = detail::load_little_endian<4>(cs.begin());
1366 d4 = detail::hex_digit(static_cast<
1367 unsigned char>(digit >> 24));
1368 d3 = detail::hex_digit(static_cast<
1369 unsigned char>(digit >> 16));
1370 d2 = detail::hex_digit(static_cast<
1371 unsigned char>(digit >> 8));
1372 d1 = detail::hex_digit(static_cast<
1373 unsigned char>(digit));
1374 if(BOOST_JSON_UNLIKELY(
1375 (d1 | d2 | d3 | d4) == -1))
1376 {
1377 if(d1 != -1)
1378 ++cs;
1379 if(d2 != -1)
1380 ++cs;
1381 if(d3 != -1)
1382 ++cs;
1383 BOOST_STATIC_CONSTEXPR source_location loc
1384 = BOOST_CURRENT_LOCATION;
1385 return fail(cs.begin(), error::expected_hex_digit, &loc);
1386 }
1387 unsigned u2 =
1388 (d1 << 12) + (d2 << 8) +
1389 (d3 << 4) + d4;
1390
1391
1392 if(BOOST_JSON_UNLIKELY(
1393 u2 < 0xdc00 || u2 > 0xdfff))
1394 {
1395
1396 if(!allow_bad_utf16)
1397 {
1398 BOOST_STATIC_CONSTEXPR source_location loc
1399 = BOOST_CURRENT_LOCATION;
1400 return fail(cs.begin(), error::illegal_trailing_surrogate,
1401 &loc);
1402 }
1403
1404
1405 cs += 4;
1406 temp.append_utf8(urc);
1407
1408
1409
1410 if (u2 < 0xd800 || u2 > 0xdbff)
1411 {
1412 temp.append_utf8(u2);
1413 break;
1414 }
1415
1416 else
1417 {
1418 u1_ = u2;
1419 goto do_sur1;
1420 }
1421 }
1422 cs += 4;
1423
1424
1425 unsigned cp =
1426 ((u1 - 0xd800) << 10) +
1427 ((u2 - 0xdc00)) +
1428 0x10000;
1429
1430 temp.append_utf8(cp);
1431 break;
1432 }
1433
1434 if(BOOST_JSON_LIKELY(! temp.empty()))
1435 {
1436 BOOST_ASSERT(total <= max_size);
1437 if(BOOST_JSON_UNLIKELY(
1438 temp.size() > max_size - total))
1439 {
1440 BOOST_STATIC_CONSTEXPR source_location loc
1441 = BOOST_CURRENT_LOCATION;
1442 return fail(cs.begin(), ev_too_large, &loc);
1443 }
1444 total += temp.size();
1445 {
1446 bool r = is_key
1447 ? h_.on_key_part(temp.get(), total, ec_)
1448 : h_.on_string_part(temp.get(), total, ec_);
1449
1450 if(BOOST_JSON_UNLIKELY(!r))
1451 {
1452 return fail(cs.begin());
1453 }
1454 }
1455 temp.clear();
1456 cs.clip(temp.max_size());
1457 }
1458 ++cs;
1459
1460 do_str4:
1461 if(BOOST_JSON_UNLIKELY(! cs))
1462 return maybe_suspend(cs.begin(), state::str4);
1463 digit = detail::hex_digit(*cs);
1464 if(BOOST_JSON_UNLIKELY(digit == -1))
1465 {
1466 BOOST_STATIC_CONSTEXPR source_location loc
1467 = BOOST_CURRENT_LOCATION;
1468 return fail(cs.begin(), error::expected_hex_digit, &loc);
1469 }
1470 ++cs;
1471 u1_ = digit << 12;
1472 do_str5:
1473 if(BOOST_JSON_UNLIKELY(! cs))
1474 return maybe_suspend(cs.begin(), state::str5);
1475 digit = detail::hex_digit(*cs);
1476 if(BOOST_JSON_UNLIKELY(digit == -1))
1477 {
1478 BOOST_STATIC_CONSTEXPR source_location loc
1479 = BOOST_CURRENT_LOCATION;
1480 return fail(cs.begin(), error::expected_hex_digit, &loc);
1481 }
1482 ++cs;
1483 u1_ += digit << 8;
1484 do_str6:
1485 if(BOOST_JSON_UNLIKELY(! cs))
1486 return maybe_suspend(cs.begin(), state::str6);
1487 digit = detail::hex_digit(*cs);
1488 if(BOOST_JSON_UNLIKELY(digit == -1))
1489 {
1490 BOOST_STATIC_CONSTEXPR source_location loc
1491 = BOOST_CURRENT_LOCATION;
1492 return fail(cs.begin(), error::expected_hex_digit, &loc);
1493 }
1494 ++cs;
1495 u1_ += digit << 4;
1496 do_str7:
1497 if(BOOST_JSON_UNLIKELY(! cs))
1498 return maybe_suspend(cs.begin(), state::str7);
1499 digit = detail::hex_digit(*cs);
1500 if(BOOST_JSON_UNLIKELY(digit == -1))
1501 {
1502 BOOST_STATIC_CONSTEXPR source_location loc
1503 = BOOST_CURRENT_LOCATION;
1504 return fail(cs.begin(), error::expected_hex_digit, &loc);
1505 }
1506 ++cs;
1507 u1_ += digit;
1508 if(BOOST_JSON_LIKELY(
1509 u1_ < 0xd800 || u1_ > 0xdfff))
1510 {
1511 BOOST_ASSERT(temp.empty());
1512
1513 temp.append_utf8(u1_);
1514 break;
1515 }
1516 if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
1517 {
1518
1519
1520 if(!allow_bad_utf16)
1521 {
1522 BOOST_STATIC_CONSTEXPR source_location loc
1523 = BOOST_CURRENT_LOCATION;
1524 return fail(cs.begin(), error::illegal_leading_surrogate, &loc);
1525 }
1526
1527 else
1528 {
1529 BOOST_ASSERT(temp.empty());
1530 temp.append_utf8(urc);
1531 break;
1532 }
1533 }
1534 do_sur1:
1535 if(BOOST_JSON_UNLIKELY(! cs))
1536 return maybe_suspend(cs.begin(), state::sur1);
1537 if(BOOST_JSON_UNLIKELY(*cs != '\\'))
1538 {
1539
1540
1541 if(!allow_bad_utf16)
1542 {
1543 BOOST_STATIC_CONSTEXPR source_location loc
1544 = BOOST_CURRENT_LOCATION;
1545 return fail(cs.begin(), error::syntax, &loc);
1546 }
1547
1548
1549 else
1550 {
1551 temp.append_utf8(urc);
1552 break;
1553 }
1554 }
1555 ++cs;
1556 do_sur2:
1557 if(BOOST_JSON_UNLIKELY(! cs))
1558 return maybe_suspend(cs.begin(), state::sur2);
1559 if(BOOST_JSON_UNLIKELY(*cs != 'u'))
1560 {
1561 if (!allow_bad_utf16)
1562 {
1563 BOOST_STATIC_CONSTEXPR source_location loc
1564 = BOOST_CURRENT_LOCATION;
1565 return fail(cs.begin(), error::syntax, &loc);
1566 }
1567
1568
1569 else
1570 {
1571 temp.append_utf8(urc);
1572 goto do_str3;
1573 }
1574 }
1575 ++cs;
1576 do_sur3:
1577 if(BOOST_JSON_UNLIKELY(! cs))
1578 return maybe_suspend(cs.begin(), state::sur3);
1579 digit = detail::hex_digit(*cs);
1580 if(BOOST_JSON_UNLIKELY(digit == -1))
1581 {
1582 BOOST_STATIC_CONSTEXPR source_location loc
1583 = BOOST_CURRENT_LOCATION;
1584 return fail(cs.begin(), error::expected_hex_digit, &loc);
1585 }
1586 ++cs;
1587 u2_ = digit << 12;
1588 do_sur4:
1589 if(BOOST_JSON_UNLIKELY(! cs))
1590 return maybe_suspend(cs.begin(), state::sur4);
1591 digit = detail::hex_digit(*cs);
1592 if(BOOST_JSON_UNLIKELY(digit == -1))
1593 {
1594 BOOST_STATIC_CONSTEXPR source_location loc
1595 = BOOST_CURRENT_LOCATION;
1596 return fail(cs.begin(), error::expected_hex_digit, &loc);
1597 }
1598 ++cs;
1599 u2_ += digit << 8;
1600 do_sur5:
1601 if(BOOST_JSON_UNLIKELY(! cs))
1602 return maybe_suspend(cs.begin(), state::sur5);
1603 digit = detail::hex_digit(*cs);
1604 if(BOOST_JSON_UNLIKELY(digit == -1))
1605 {
1606 BOOST_STATIC_CONSTEXPR source_location loc
1607 = BOOST_CURRENT_LOCATION;
1608 return fail(cs.begin(), error::expected_hex_digit, &loc);
1609 }
1610 ++cs;
1611 u2_ += digit << 4;
1612 do_sur6:
1613 if(BOOST_JSON_UNLIKELY(! cs))
1614 return maybe_suspend(cs.begin(), state::sur6);
1615 digit = detail::hex_digit(*cs);
1616 if(BOOST_JSON_UNLIKELY(digit == -1))
1617 {
1618 BOOST_STATIC_CONSTEXPR source_location loc
1619 = BOOST_CURRENT_LOCATION;
1620 return fail(cs.begin(), error::expected_hex_digit, &loc);
1621 }
1622 ++cs;
1623 u2_ += digit;
1624
1625
1626 if(BOOST_JSON_UNLIKELY(
1627 u2_ < 0xdc00 || u2_ > 0xdfff))
1628 {
1629
1630 if(!allow_bad_utf16)
1631 {
1632 BOOST_STATIC_CONSTEXPR source_location loc
1633 = BOOST_CURRENT_LOCATION;
1634 return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
1635 }
1636
1637
1638 temp.append_utf8(urc);
1639
1640
1641
1642 if (u2_ < 0xd800 || u2_ > 0xdbff)
1643 {
1644 temp.append_utf8(u2_);
1645 break;
1646 }
1647
1648 else
1649 {
1650 u1_ = u2_;
1651 goto do_sur1;
1652 }
1653 }
1654
1655
1656 unsigned cp =
1657 ((u1_ - 0xd800) << 10) +
1658 ((u2_ - 0xdc00)) +
1659 0x10000;
1660
1661 temp.append_utf8(cp);
1662 }
1663
1664
1665 if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
1666 break;
1667 }
1668
1669 if(BOOST_JSON_LIKELY( temp.size() ))
1670 {
1671 BOOST_ASSERT(total <= max_size);
1672 if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
1673 {
1674 BOOST_STATIC_CONSTEXPR source_location loc
1675 = BOOST_CURRENT_LOCATION;
1676 return fail(cs.begin(), ev_too_large, &loc);
1677 }
1678
1679 total += temp.size();
1680 bool const r = is_key
1681 ? h_.on_key_part(temp.get(), total, ec_)
1682 : h_.on_string_part(temp.get(), total, ec_);
1683 if(BOOST_JSON_UNLIKELY( !r ))
1684 return fail( cs.begin() );
1685 }
1686
1687 return cs.begin();
1688 }
1689
1690
1691
1692 template<class Handler>
1693 template<
1694 bool StackEmpty_,
1695 bool AllowComments_
1696
1697 >
1698 const char*
1699 basic_parser<Handler>::
1700 parse_object(const char* p,
1701 std::integral_constant<bool, StackEmpty_> stack_empty,
1702 std::integral_constant<bool, AllowComments_> allow_comments,
1703 bool allow_trailing,
1704 bool allow_bad_utf8,
1705 bool allow_bad_utf16)
1706 {
1707 detail::const_stream_wrapper cs(p, end_);
1708 std::size_t size;
1709 if(! stack_empty && ! st_.empty())
1710 {
1711
1712 state st;
1713 st_.pop(st);
1714 st_.pop(size);
1715 switch(st)
1716 {
1717 default: BOOST_JSON_UNREACHABLE();
1718 case state::obj1: goto do_obj1;
1719 case state::obj2: goto do_obj2;
1720 case state::obj3: goto do_obj3;
1721 case state::obj4: goto do_obj4;
1722 case state::obj5: goto do_obj5;
1723 case state::obj6: goto do_obj6;
1724 case state::obj7: goto do_obj7;
1725 case state::obj8: goto do_obj8;
1726 case state::obj9: goto do_obj9;
1727 case state::obj10: goto do_obj10;
1728 case state::obj11: goto do_obj11;
1729 }
1730 }
1731 BOOST_ASSERT(*cs == '{');
1732 size = 0;
1733 if(BOOST_JSON_UNLIKELY(! depth_))
1734 {
1735 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1736 return fail(cs.begin(), error::too_deep, &loc);
1737 }
1738 --depth_;
1739 if(BOOST_JSON_UNLIKELY(
1740 ! h_.on_object_begin(ec_)))
1741 return fail(cs.begin());
1742 ++cs;
1743
1744
1745
1746 do_obj1:
1747 cs = detail::count_whitespace(cs.begin(), cs.end());
1748 if(BOOST_JSON_UNLIKELY(! cs))
1749 return maybe_suspend(cs.begin(), state::obj1, size);
1750 if(BOOST_JSON_LIKELY(*cs != '}'))
1751 {
1752 if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
1753 {
1754 if(allow_comments && *cs == '/')
1755 {
1756 do_obj2:
1757 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1758 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1759 return suspend_or_fail(state::obj2, size);
1760 goto do_obj1;
1761 }
1762 BOOST_STATIC_CONSTEXPR source_location loc
1763 = BOOST_CURRENT_LOCATION;
1764 return fail(cs.begin(), error::syntax, &loc);
1765 }
1766 loop:
1767 if(BOOST_JSON_UNLIKELY(++size >
1768 Handler::max_object_size))
1769 {
1770 BOOST_STATIC_CONSTEXPR source_location loc
1771 = BOOST_CURRENT_LOCATION;
1772 return fail(cs.begin(), error::object_too_large, &loc);
1773 }
1774 do_obj3:
1775 cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
1776 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1777 return suspend_or_fail(state::obj3, size);
1778 do_obj4:
1779 cs = detail::count_whitespace(cs.begin(), cs.end());
1780 if(BOOST_JSON_UNLIKELY(! cs))
1781 return maybe_suspend(cs.begin(), state::obj4, size);
1782 if(BOOST_JSON_UNLIKELY(*cs != ':'))
1783 {
1784 if(allow_comments && *cs == '/')
1785 {
1786 do_obj5:
1787 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1788 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1789 return suspend_or_fail(state::obj5, size);
1790 goto do_obj4;
1791 }
1792 BOOST_STATIC_CONSTEXPR source_location loc
1793 = BOOST_CURRENT_LOCATION;
1794 return fail(cs.begin(), error::syntax, &loc);
1795 }
1796 ++cs;
1797 do_obj6:
1798 cs = detail::count_whitespace(cs.begin(), cs.end());
1799 if(BOOST_JSON_UNLIKELY(! cs))
1800 return maybe_suspend(cs.begin(), state::obj6, size);
1801 do_obj7:
1802 cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1803 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1804 return suspend_or_fail(state::obj7, size);
1805 do_obj8:
1806 cs = detail::count_whitespace(cs.begin(), cs.end());
1807 if(BOOST_JSON_UNLIKELY(! cs))
1808 return maybe_suspend(cs.begin(), state::obj8, size);
1809 if(BOOST_JSON_LIKELY(*cs == ','))
1810 {
1811 ++cs;
1812 do_obj9:
1813 cs = detail::count_whitespace(cs.begin(), cs.end());
1814 if(BOOST_JSON_UNLIKELY(! cs))
1815 return maybe_suspend(cs.begin(), state::obj9, size);
1816
1817
1818 if(BOOST_JSON_LIKELY(*cs == '\x22'))
1819 goto loop;
1820 if(! allow_trailing || *cs != '}')
1821 {
1822 if(allow_comments && *cs == '/')
1823 {
1824 do_obj10:
1825 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1826 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1827 return suspend_or_fail(state::obj10, size);
1828 goto do_obj9;
1829 }
1830 BOOST_STATIC_CONSTEXPR source_location loc
1831 = BOOST_CURRENT_LOCATION;
1832 return fail(cs.begin(), error::syntax, &loc);
1833 }
1834 }
1835 else if(BOOST_JSON_UNLIKELY(*cs != '}'))
1836 {
1837 if(allow_comments && *cs == '/')
1838 {
1839 do_obj11:
1840 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1841 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1842 return suspend_or_fail(state::obj11, size);
1843 goto do_obj8;
1844 }
1845 BOOST_STATIC_CONSTEXPR source_location loc
1846 = BOOST_CURRENT_LOCATION;
1847 return fail(cs.begin(), error::syntax, &loc);
1848 }
1849
1850 }
1851 if(BOOST_JSON_UNLIKELY(
1852 ! h_.on_object_end(size, ec_)))
1853 return fail(cs.begin());
1854 ++depth_;
1855 ++cs;
1856 return cs.begin();
1857 }
1858
1859
1860
1861 template<class Handler>
1862 template<
1863 bool StackEmpty_,
1864 bool AllowComments_
1865
1866 >
1867 const char*
1868 basic_parser<Handler>::
1869 parse_array(const char* p,
1870 std::integral_constant<bool, StackEmpty_> stack_empty,
1871 std::integral_constant<bool, AllowComments_> allow_comments,
1872 bool allow_trailing,
1873 bool allow_bad_utf8,
1874 bool allow_bad_utf16)
1875 {
1876 detail::const_stream_wrapper cs(p, end_);
1877 std::size_t size;
1878 if(! stack_empty && ! st_.empty())
1879 {
1880
1881 state st;
1882 st_.pop(st);
1883 st_.pop(size);
1884 switch(st)
1885 {
1886 default: BOOST_JSON_UNREACHABLE();
1887 case state::arr1: goto do_arr1;
1888 case state::arr2: goto do_arr2;
1889 case state::arr3: goto do_arr3;
1890 case state::arr4: goto do_arr4;
1891 case state::arr5: goto do_arr5;
1892 case state::arr6: goto do_arr6;
1893 }
1894 }
1895 BOOST_ASSERT(*cs == '[');
1896 size = 0;
1897 if(BOOST_JSON_UNLIKELY(! depth_))
1898 {
1899 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
1900 return fail(cs.begin(), error::too_deep, &loc);
1901 }
1902 --depth_;
1903 if(BOOST_JSON_UNLIKELY(
1904 ! h_.on_array_begin(ec_)))
1905 return fail(cs.begin());
1906 ++cs;
1907
1908
1909
1910 do_arr1:
1911 cs = detail::count_whitespace(cs.begin(), cs.end());
1912 if(BOOST_JSON_UNLIKELY(! cs))
1913 return maybe_suspend(cs.begin(), state::arr1, size);
1914 if(BOOST_JSON_LIKELY(*cs != ']'))
1915 {
1916 loop:
1917 if(allow_comments && *cs == '/')
1918 {
1919 do_arr2:
1920 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1921 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1922 return suspend_or_fail(state::arr2, size);
1923 goto do_arr1;
1924 }
1925 if(BOOST_JSON_UNLIKELY(++size >
1926 Handler::max_array_size))
1927 {
1928 BOOST_STATIC_CONSTEXPR source_location loc
1929 = BOOST_CURRENT_LOCATION;
1930 return fail(cs.begin(), error::array_too_large, &loc);
1931 }
1932 do_arr3:
1933
1934 cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
1935 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1936 return suspend_or_fail(state::arr3, size);
1937 do_arr4:
1938 cs = detail::count_whitespace(cs.begin(), cs.end());
1939 if(BOOST_JSON_UNLIKELY(! cs))
1940 return maybe_suspend(cs.begin(), state::arr4, size);
1941 if(BOOST_JSON_LIKELY(*cs == ','))
1942 {
1943 ++cs;
1944 do_arr5:
1945 cs = detail::count_whitespace(cs.begin(), cs.end());
1946 if(BOOST_JSON_UNLIKELY(! cs))
1947 return maybe_suspend(cs.begin(), state::arr5, size);
1948
1949 if(! allow_trailing || *cs != ']')
1950 goto loop;
1951 }
1952 else if(BOOST_JSON_UNLIKELY(*cs != ']'))
1953 {
1954 if(allow_comments && *cs == '/')
1955 {
1956 do_arr6:
1957 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
1958 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
1959 return suspend_or_fail(state::arr6, size);
1960 goto do_arr4;
1961 }
1962 BOOST_STATIC_CONSTEXPR source_location loc
1963 = BOOST_CURRENT_LOCATION;
1964 return fail(cs.begin(), error::syntax, &loc);
1965 }
1966
1967 }
1968 if(BOOST_JSON_UNLIKELY(
1969 ! h_.on_array_end(size, ec_)))
1970 return fail(cs.begin());
1971 ++depth_;
1972 ++cs;
1973 return cs.begin();
1974 }
1975
1976
1977
1978 template<class Handler>
1979 template<bool StackEmpty_, char First_, number_precision Numbers_>
1980 const char*
1981 basic_parser<Handler>::
1982 parse_number(const char* p,
1983 std::integral_constant<bool, StackEmpty_> stack_empty,
1984 std::integral_constant<char, First_> first,
1985 std::integral_constant<number_precision, Numbers_> mode)
1986 {
1987 constexpr bool precise_parsing = mode == number_precision::precise;
1988 constexpr bool no_parsing = mode == number_precision::none;
1989
1990
1991
1992
1993
1994 bool const negative = first == '-';
1995 bool const zero_first = first == '0';
1996 bool const nonzero_first = first == '+';
1997 detail::const_stream_wrapper cs(p, end_);
1998 number num;
1999 const char* begin = cs.begin();
2000 if(stack_empty || st_.empty())
2001 {
2002 num.bias = 0;
2003 num.exp = 0;
2004 num.frac = false;
2005 num_buf_.clear();
2006
2007
2008
2009
2010
2011
2012 BOOST_ASSERT(cs);
2013 if(negative)
2014 ++cs;
2015
2016 num.neg = negative;
2017 num.frac = false;
2018 num.exp = 0;
2019 num.bias = 0;
2020
2021
2022 if( cs.remain() >= 16 + 1 + 16 )
2023 {
2024 int n1;
2025
2026 if( nonzero_first ||
2027 (negative && *cs != '0') )
2028 {
2029 n1 = detail::count_digits( cs.begin() );
2030 BOOST_ASSERT(n1 >= 0 && n1 <= 16);
2031
2032 if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
2033 {
2034 return parse_literal(
2035 p - 1,
2036 detail::literals_c<detail::literals::neg_infinity>());
2037 }
2038
2039 if( ! nonzero_first && n1 == 0 )
2040 {
2041
2042 BOOST_STATIC_CONSTEXPR source_location loc
2043 = BOOST_CURRENT_LOCATION;
2044 return fail(cs.begin(), error::syntax, &loc);
2045 }
2046
2047 BOOST_IF_CONSTEXPR( !no_parsing )
2048 num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
2049 else
2050 num.mant = 0;
2051
2052 cs += n1;
2053
2054
2055
2056 if( n1 == 16 )
2057 {
2058 goto do_num2;
2059 }
2060 }
2061 else
2062 {
2063
2064 num.mant = 0;
2065 n1 = 0;
2066 ++cs;
2067 }
2068
2069 {
2070 const char c = *cs;
2071 if(c != '.')
2072 {
2073 if((c | 32) == 'e')
2074 {
2075 ++cs;
2076 goto do_exp1;
2077 }
2078 BOOST_IF_CONSTEXPR( negative && !no_parsing )
2079 num.mant = ~num.mant + 1;
2080 goto finish_signed;
2081 }
2082 }
2083
2084
2085
2086 ++cs;
2087
2088 int n2 = detail::count_digits( cs.begin() );
2089 BOOST_ASSERT(n2 >= 0 && n2 <= 16);
2090
2091 if( n2 == 0 )
2092 {
2093
2094 BOOST_STATIC_CONSTEXPR source_location loc
2095 = BOOST_CURRENT_LOCATION;
2096 return fail(cs.begin(), error::syntax, &loc);
2097 }
2098
2099
2100 if( n1 + n2 >= 19 )
2101 {
2102 goto do_num7;
2103 }
2104
2105 BOOST_IF_CONSTEXPR( !no_parsing )
2106 num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
2107
2108 BOOST_ASSERT(num.bias == 0);
2109
2110 num.bias -= n2;
2111
2112 cs += n2;
2113
2114 char ch = *cs;
2115
2116 if( (ch | 32) == 'e' )
2117 {
2118 ++cs;
2119 goto do_exp1;
2120 }
2121 else if( ch >= '0' && ch <= '9' )
2122 {
2123 goto do_num8;
2124 }
2125
2126 goto finish_dub;
2127 }
2128 }
2129 else
2130 {
2131 num = num_;
2132 state st;
2133 st_.pop(st);
2134 switch(st)
2135 {
2136 default: BOOST_JSON_UNREACHABLE();
2137 case state::num1: goto do_num1;
2138 case state::num2: goto do_num2;
2139 case state::num3: goto do_num3;
2140 case state::num4: goto do_num4;
2141 case state::num5: goto do_num5;
2142 case state::num6: goto do_num6;
2143 case state::num7: goto do_num7;
2144 case state::num8: goto do_num8;
2145 case state::exp1: goto do_exp1;
2146 case state::exp2: goto do_exp2;
2147 case state::exp3: goto do_exp3;
2148 }
2149 }
2150
2151
2152
2153
2154
2155
2156 do_num1:
2157 if(zero_first || nonzero_first ||
2158 BOOST_JSON_LIKELY(cs))
2159 {
2160 char const c = *cs;
2161 if(zero_first)
2162 {
2163 ++cs;
2164 num.mant = 0;
2165 goto do_num6;
2166 }
2167 else if(nonzero_first || BOOST_JSON_LIKELY(
2168 c >= '1' && c <= '9'))
2169 {
2170 ++cs;
2171 num.mant = c - '0';
2172 }
2173 else if(BOOST_JSON_UNLIKELY(
2174 c == '0'))
2175 {
2176 ++cs;
2177 num.mant = 0;
2178 goto do_num6;
2179 }
2180 else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
2181 {
2182 st_.push(state::lit1);
2183 cur_lit_ = literal_index(detail::literals::neg_infinity);
2184 lit_offset_ = 1;
2185 return parse_literal(
2186 cs.begin(), detail::literals_c<detail::literals::resume>() );
2187 }
2188 else
2189 {
2190 BOOST_STATIC_CONSTEXPR source_location loc
2191 = BOOST_CURRENT_LOCATION;
2192 return fail(cs.begin(), error::syntax, &loc);
2193 }
2194 }
2195 else
2196 {
2197 if(BOOST_JSON_UNLIKELY(
2198 ! h_.on_number_part(
2199 {begin, cs.used(begin)}, ec_)))
2200 return fail(cs.begin());
2201
2202 BOOST_IF_CONSTEXPR( precise_parsing )
2203 num_buf_.append( begin, cs.used(begin) );
2204 return maybe_suspend(
2205 cs.begin(), state::num1, num);
2206 }
2207
2208
2209
2210
2211
2212
2213 do_num2:
2214 if(negative || (!stack_empty && num.neg))
2215 {
2216 for(;;)
2217 {
2218 if(BOOST_JSON_UNLIKELY(! cs))
2219 {
2220 if(BOOST_JSON_UNLIKELY(more_))
2221 {
2222 if(BOOST_JSON_UNLIKELY(
2223 ! h_.on_number_part(
2224 {begin, cs.used(begin)}, ec_)))
2225 return fail(cs.begin());
2226
2227 BOOST_IF_CONSTEXPR( precise_parsing )
2228 num_buf_.append( begin, cs.used(begin) );
2229 return suspend(cs.begin(), state::num2, num);
2230 }
2231 goto finish_int;
2232 }
2233 char const c = *cs;
2234 if(BOOST_JSON_LIKELY(
2235 c >= '0' && c <= '9'))
2236 {
2237 ++cs;
2238
2239 if( num.mant > 922337203685477580 || (
2240 num.mant == 922337203685477580 && c > '8'))
2241 break;
2242 BOOST_IF_CONSTEXPR( !no_parsing )
2243 num.mant = 10 * num.mant + ( c - '0' );
2244 continue;
2245 }
2246 goto do_num6;
2247 }
2248 }
2249 else
2250 {
2251 for(;;)
2252 {
2253 if(BOOST_JSON_UNLIKELY(! cs))
2254 {
2255 if(BOOST_JSON_UNLIKELY(more_))
2256 {
2257 if(BOOST_JSON_UNLIKELY(
2258 ! h_.on_number_part(
2259 {begin, cs.used(begin)}, ec_)))
2260 return fail(cs.begin());
2261
2262 BOOST_IF_CONSTEXPR( precise_parsing )
2263 num_buf_.append( begin, cs.used(begin) );
2264 return suspend(cs.begin(), state::num2, num);
2265 }
2266 goto finish_int;
2267 }
2268 char const c = *cs;
2269 if(BOOST_JSON_LIKELY(
2270 c >= '0' && c <= '9'))
2271 {
2272 ++cs;
2273
2274 if( num.mant > 1844674407370955161 || (
2275 num.mant == 1844674407370955161 && c > '5'))
2276 break;
2277 BOOST_IF_CONSTEXPR( !no_parsing )
2278 num.mant = 10 * num.mant + ( c - '0' );
2279 }
2280 else
2281 {
2282 goto do_num6;
2283 }
2284 }
2285 }
2286 ++num.bias;
2287
2288
2289
2290
2291
2292
2293 do_num3:
2294 for(;;)
2295 {
2296 if(BOOST_JSON_UNLIKELY(! cs))
2297 {
2298 if(BOOST_JSON_UNLIKELY(more_))
2299 {
2300 if(BOOST_JSON_UNLIKELY(
2301 ! h_.on_number_part(
2302 {begin, cs.used(begin)}, ec_)))
2303 return fail(cs.begin());
2304
2305 BOOST_IF_CONSTEXPR( precise_parsing )
2306 num_buf_.append( begin, cs.used(begin) );
2307 return suspend(cs.begin(), state::num3, num);
2308 }
2309 goto finish_dub;
2310 }
2311 char const c = *cs;
2312 if(BOOST_JSON_UNLIKELY(
2313 c >= '0' && c <= '9'))
2314 {
2315 if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
2316 {
2317 BOOST_STATIC_CONSTEXPR source_location loc
2318 = BOOST_CURRENT_LOCATION;
2319 return fail(cs.begin(), error::exponent_overflow, &loc);
2320 }
2321 ++cs;
2322 ++num.bias;
2323 }
2324 else if(BOOST_JSON_LIKELY(
2325 c == '.'))
2326 {
2327 ++cs;
2328 break;
2329 }
2330 else if((c | 32) == 'e')
2331 {
2332 ++cs;
2333 goto do_exp1;
2334 }
2335 else
2336 {
2337 goto finish_dub;
2338 }
2339 }
2340
2341
2342
2343
2344
2345
2346
2347 do_num4:
2348 {
2349 if(BOOST_JSON_UNLIKELY(! cs))
2350 {
2351 if(BOOST_JSON_UNLIKELY(
2352 ! h_.on_number_part(
2353 {begin, cs.used(begin)}, ec_)))
2354 return fail(cs.begin());
2355
2356 BOOST_IF_CONSTEXPR( precise_parsing )
2357 num_buf_.append( begin, cs.used(begin) );
2358 return maybe_suspend(
2359 cs.begin(), state::num4, num);
2360 }
2361 char const c = *cs;
2362 if(BOOST_JSON_LIKELY(
2363
2364 c >= '0' && c <= '9'))
2365 {
2366 ++cs;
2367 }
2368 else
2369 {
2370
2371 BOOST_STATIC_CONSTEXPR source_location loc
2372 = BOOST_CURRENT_LOCATION;
2373 return fail(cs.begin(), error::syntax, &loc);
2374 }
2375 }
2376
2377
2378
2379
2380
2381
2382
2383 do_num5:
2384 for(;;)
2385 {
2386 if(BOOST_JSON_UNLIKELY(! cs))
2387 {
2388 if(BOOST_JSON_UNLIKELY(more_))
2389 {
2390 if(BOOST_JSON_UNLIKELY(
2391 ! h_.on_number_part(
2392 {begin, cs.used(begin)}, ec_)))
2393 return fail(cs.begin());
2394
2395 BOOST_IF_CONSTEXPR( precise_parsing )
2396 num_buf_.append( begin, cs.used(begin) );
2397 return suspend(cs.begin(), state::num5, num);
2398 }
2399 goto finish_dub;
2400 }
2401 char const c = *cs;
2402 if(BOOST_JSON_LIKELY(
2403 c >= '0' && c <= '9'))
2404 {
2405 ++cs;
2406 }
2407 else if((c | 32) == 'e')
2408 {
2409 ++cs;
2410 goto do_exp1;
2411 }
2412 else
2413 {
2414 goto finish_dub;
2415 }
2416 }
2417
2418
2419
2420
2421
2422 do_num6:
2423 {
2424 if(BOOST_JSON_UNLIKELY(! cs))
2425 {
2426 if(BOOST_JSON_UNLIKELY(more_))
2427 {
2428 if(BOOST_JSON_UNLIKELY(
2429 ! h_.on_number_part(
2430 {begin, cs.used(begin)}, ec_)))
2431 return fail(cs.begin());
2432
2433 BOOST_IF_CONSTEXPR( precise_parsing )
2434 num_buf_.append( begin, cs.used(begin) );
2435 return suspend(cs.begin(), state::num6, num);
2436 }
2437 goto finish_int;
2438 }
2439 char const c = *cs;
2440 if(BOOST_JSON_LIKELY(
2441 c == '.'))
2442 {
2443 ++cs;
2444 }
2445 else if((c | 32) == 'e')
2446 {
2447 ++cs;
2448 goto do_exp1;
2449 }
2450 else
2451 {
2452 goto finish_int;
2453 }
2454 }
2455
2456
2457
2458
2459
2460
2461
2462 do_num7:
2463 {
2464 if(BOOST_JSON_UNLIKELY(! cs))
2465 {
2466 if(BOOST_JSON_UNLIKELY(more_))
2467 {
2468 if(BOOST_JSON_UNLIKELY(
2469 ! h_.on_number_part(
2470 {begin, cs.used(begin)}, ec_)))
2471 return fail(cs.begin());
2472
2473 BOOST_IF_CONSTEXPR( precise_parsing )
2474 num_buf_.append( begin, cs.used(begin) );
2475 return suspend(cs.begin(), state::num7, num);
2476 }
2477
2478 BOOST_STATIC_CONSTEXPR source_location loc
2479 = BOOST_CURRENT_LOCATION;
2480 return fail(cs.begin(), error::syntax, &loc);
2481 }
2482 char const c = *cs;
2483 if(BOOST_JSON_UNLIKELY(
2484 c < '0' || c > '9'))
2485 {
2486
2487 BOOST_STATIC_CONSTEXPR source_location loc
2488 = BOOST_CURRENT_LOCATION;
2489 return fail(cs.begin(), error::syntax, &loc);
2490 }
2491 }
2492
2493
2494
2495
2496
2497
2498
2499 do_num8:
2500 for(;;)
2501 {
2502 if(BOOST_JSON_UNLIKELY(! cs))
2503 {
2504 if(BOOST_JSON_UNLIKELY(more_))
2505 {
2506 if(BOOST_JSON_UNLIKELY(
2507 ! h_.on_number_part(
2508 {begin, cs.used(begin)}, ec_)))
2509 return fail(cs.begin());
2510
2511 BOOST_IF_CONSTEXPR( precise_parsing )
2512 num_buf_.append( begin, cs.used(begin) );
2513 return suspend(cs.begin(), state::num8, num);
2514 }
2515 goto finish_dub;
2516 }
2517 char const c = *cs;
2518 if(BOOST_JSON_LIKELY(
2519 c >= '0' && c <= '9'))
2520 {
2521 ++cs;
2522 if(!no_parsing && BOOST_JSON_LIKELY(
2523 num.mant <= 9007199254740991))
2524 {
2525 if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
2526 {
2527 BOOST_STATIC_CONSTEXPR source_location loc
2528 = BOOST_CURRENT_LOCATION;
2529 return fail(cs.begin(), error::exponent_overflow, &loc);
2530 }
2531 --num.bias;
2532 num.mant = 10 * num.mant + ( c - '0' );
2533 }
2534 else
2535 {
2536 goto do_num5;
2537 }
2538 }
2539 else if((c | 32) == 'e')
2540 {
2541 ++cs;
2542 goto do_exp1;
2543 }
2544 else
2545 {
2546 goto finish_dub;
2547 }
2548 }
2549
2550
2551
2552
2553
2554 do_exp1:
2555 if(BOOST_JSON_UNLIKELY(! cs))
2556 {
2557 if(BOOST_JSON_UNLIKELY(
2558 ! h_.on_number_part(
2559 {begin, cs.used(begin)}, ec_)))
2560 return fail(cs.begin());
2561
2562 BOOST_IF_CONSTEXPR( precise_parsing )
2563 num_buf_.append( begin, cs.used(begin) );
2564 return maybe_suspend(
2565 cs.begin(), state::exp1, num);
2566 }
2567 if(*cs == '+')
2568 {
2569 ++cs;
2570 }
2571 else if(*cs == '-')
2572 {
2573 ++cs;
2574 num.frac = true;
2575 }
2576
2577
2578
2579
2580
2581
2582 do_exp2:
2583 {
2584 if(BOOST_JSON_UNLIKELY(! cs))
2585 {
2586 if(BOOST_JSON_UNLIKELY(more_))
2587 {
2588 if(BOOST_JSON_UNLIKELY(
2589 ! h_.on_number_part(
2590 {begin, cs.used(begin)}, ec_)))
2591 return fail(cs.begin());
2592
2593 BOOST_IF_CONSTEXPR( precise_parsing )
2594 num_buf_.append( begin, cs.used(begin) );
2595 return suspend(cs.begin(), state::exp2, num);
2596 }
2597
2598 BOOST_STATIC_CONSTEXPR source_location loc
2599 = BOOST_CURRENT_LOCATION;
2600 return fail(cs.begin(), error::syntax, &loc);
2601 }
2602 char const c = *cs;
2603 if(BOOST_JSON_UNLIKELY(
2604 c < '0' || c > '9'))
2605 {
2606
2607 BOOST_STATIC_CONSTEXPR source_location loc
2608 = BOOST_CURRENT_LOCATION;
2609 return fail(cs.begin(), error::syntax, &loc);
2610 }
2611 ++cs;
2612 num.exp = c - '0';
2613 }
2614
2615
2616
2617
2618
2619
2620 do_exp3:
2621 for(;;)
2622 {
2623 if(BOOST_JSON_UNLIKELY(! cs))
2624 {
2625 if(BOOST_JSON_UNLIKELY(more_))
2626 {
2627 if(BOOST_JSON_UNLIKELY(
2628 ! h_.on_number_part(
2629 {begin, cs.used(begin)}, ec_)))
2630 return fail(cs.begin());
2631
2632 BOOST_IF_CONSTEXPR( precise_parsing )
2633 num_buf_.append( begin, cs.used(begin) );
2634 return suspend(cs.begin(), state::exp3, num);
2635 }
2636 }
2637 else
2638 {
2639 char const c = *cs;
2640 if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
2641 {
2642 if(BOOST_JSON_UNLIKELY(
2643
2644 num.exp > 214748364 ||
2645 (num.exp == 214748364 && c > '7')
2646 ))
2647 num.exp = INT_MAX;
2648 else BOOST_IF_CONSTEXPR( !no_parsing )
2649 num.exp = 10 * num.exp + ( c - '0' );
2650
2651 ++cs;
2652 continue;
2653 }
2654 }
2655 BOOST_ASSERT(num.exp >= 0);
2656 if ( num.frac )
2657 {
2658 if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
2659 {
2660
2661
2662
2663 if(BOOST_JSON_UNLIKELY(
2664 (num.exp == INT_MAX) &&
2665 (num.bias < 0) &&
2666 (num.exp + num.bias < 308) &&
2667 num.mant ))
2668 {
2669 BOOST_STATIC_CONSTEXPR source_location loc
2670 = BOOST_CURRENT_LOCATION;
2671 return fail(cs.begin(), error::exponent_overflow, &loc);
2672 }
2673
2674 num.bias = 0;
2675 num.exp = INT_MAX;
2676 }
2677 }
2678 else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
2679 {
2680
2681
2682
2683 if(BOOST_JSON_UNLIKELY(
2684 (num.exp == INT_MAX) &&
2685 (num.bias > 0) &&
2686 (num.exp - num.bias < 308) &&
2687 num.mant ))
2688 {
2689 BOOST_STATIC_CONSTEXPR source_location loc
2690 = BOOST_CURRENT_LOCATION;
2691 return fail(cs.begin(), error::exponent_overflow, &loc);
2692 }
2693
2694 num.bias = 0;
2695 num.exp = INT_MAX;
2696 }
2697 goto finish_dub;
2698 }
2699
2700 finish_int:
2701 if(negative || (!stack_empty && num.neg))
2702 {
2703 if(BOOST_JSON_UNLIKELY(
2704 ! h_.on_int64(static_cast<
2705 int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
2706 return fail(cs.begin());
2707 return cs.begin();
2708 }
2709 if(num.mant <= INT64_MAX)
2710 {
2711 finish_signed:
2712 if(BOOST_JSON_UNLIKELY(
2713 ! h_.on_int64(static_cast<
2714 int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
2715 return fail(cs.begin());
2716 return cs.begin();
2717 }
2718 if(BOOST_JSON_UNLIKELY(
2719 ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
2720 return fail(cs.begin());
2721 return cs.begin();
2722 finish_dub:
2723 double d;
2724 std::size_t const size = cs.used(begin);
2725 BOOST_ASSERT( !num_buf_.size() || precise_parsing );
2726 BOOST_IF_CONSTEXPR( precise_parsing )
2727 {
2728 char const* data = begin;
2729 std::size_t full_size = size;
2730
2731
2732
2733 if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
2734 {
2735 data = num_buf_.append( begin, size );
2736 full_size = num_buf_.size();
2737 }
2738 auto const err = detail::charconv::from_chars(
2739 data, data + full_size, d );
2740 BOOST_ASSERT( err.ec != std::errc::invalid_argument );
2741 BOOST_ASSERT( err.ptr == data + full_size );
2742 (void)err;
2743 }
2744 else BOOST_IF_CONSTEXPR( no_parsing )
2745 d = 0;
2746 else
2747 d = detail::dec_to_float(
2748 num.mant,
2749 num.bias + (num.frac ?
2750 -num.exp : num.exp),
2751 num.neg);
2752 if(BOOST_JSON_UNLIKELY(
2753 ! h_.on_double(d, {begin, size}, ec_)))
2754 return fail(cs.begin());
2755 return cs.begin();
2756 }
2757
2758
2759
2760 template<class Handler>
2761 template<class... Args>
2762 basic_parser<Handler>::
2763 basic_parser(
2764 parse_options const& opt,
2765 Args&&... args)
2766 : h_(std::forward<Args>(args)...)
2767 , opt_(opt)
2768 {
2769 }
2770
2771
2772
2773 template<class Handler>
2774 void
2775 basic_parser<Handler>::
2776 reset() noexcept
2777 {
2778 ec_ = {};
2779 st_.clear();
2780 more_ = true;
2781 done_ = false;
2782 clean_ = true;
2783 num_buf_.clear();
2784 }
2785
2786 template<class Handler>
2787 void
2788 basic_parser<Handler>::
2789 fail(system::error_code ec) noexcept
2790 {
2791 if(! ec)
2792 {
2793
2794
2795 BOOST_JSON_FAIL(ec_, error::incomplete);
2796 }
2797 else
2798 {
2799 ec_ = ec;
2800 }
2801 done_ = false;
2802 }
2803
2804
2805
2806 template<class Handler>
2807 std::size_t
2808 basic_parser<Handler>::
2809 write_some(
2810 bool more,
2811 char const* data,
2812 std::size_t size,
2813 system::error_code& ec)
2814 {
2815
2816
2817 if(! clean_)
2818 {
2819
2820 if(! ec_)
2821 {
2822 BOOST_JSON_FAIL(ec_, error::exception);
2823 }
2824 }
2825 if(ec_)
2826 {
2827
2828 ec = ec_;
2829 return 0;
2830 }
2831 clean_ = false;
2832 more_ = more;
2833 end_ = data + size;
2834 const char* p;
2835 if(BOOST_JSON_LIKELY(st_.empty()))
2836 {
2837
2838 depth_ = opt_.max_depth;
2839 if(BOOST_JSON_UNLIKELY(
2840 ! h_.on_document_begin(ec_)))
2841 {
2842 ec = ec_;
2843 return 0;
2844 }
2845 p = parse_document(data, std::true_type());
2846 }
2847 else
2848 {
2849 p = parse_document(data, std::false_type());
2850 }
2851
2852 if(BOOST_JSON_LIKELY(p != sentinel()))
2853 {
2854 BOOST_ASSERT(! ec_);
2855 if(! done_)
2856 {
2857 done_ = true;
2858 h_.on_document_end(ec_);
2859 }
2860 }
2861 else
2862 {
2863 if(! ec_)
2864 {
2865 if(! more_)
2866 {
2867 BOOST_JSON_FAIL(ec_, error::incomplete);
2868 }
2869 else if(! st_.empty())
2870 {
2871
2872
2873
2874 state st;
2875 st_.peek(st);
2876 if( st == state::doc3 &&
2877 ! done_)
2878 {
2879 done_ = true;
2880 h_.on_document_end(ec_);
2881 }
2882 }
2883 }
2884 p = end_;
2885 }
2886 ec = ec_;
2887 clean_ = true;
2888 return p - data;
2889 }
2890
2891 template<class Handler>
2892 std::size_t
2893 basic_parser<Handler>::
2894 write_some(
2895 bool more,
2896 char const* data,
2897 std::size_t size,
2898 std::error_code& ec)
2899 {
2900 system::error_code jec;
2901 std::size_t const result = write_some(more, data, size, jec);
2902 ec = jec;
2903 return result;
2904 }
2905
2906 #endif
2907
2908 }
2909 }
2910
2911 #ifdef _MSC_VER
2912 #pragma warning(pop)
2913 #endif
2914
2915 #endif