Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:04

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