Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:34:47

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