LCOV - code coverage report
Current view: top level - json - basic_parser_impl.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 98.1 % 1283 1259
Test Date: 2025-12-23 17:21:58 Functions: 36.3 % 3953 1434

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
       4              : //
       5              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7              : //
       8              : // Official repository: https://github.com/boostorg/json
       9              : //
      10              : 
      11              : #ifndef BOOST_JSON_BASIC_PARSER_IMPL_HPP
      12              : #define BOOST_JSON_BASIC_PARSER_IMPL_HPP
      13              : 
      14              : #include <boost/json/detail/config.hpp>
      15              : #include <boost/json/basic_parser.hpp>
      16              : #include <boost/json/error.hpp>
      17              : #include <boost/json/detail/buffer.hpp>
      18              : #include <boost/json/detail/charconv/from_chars.hpp>
      19              : #include <boost/json/detail/sse2.hpp>
      20              : #include <boost/mp11/algorithm.hpp>
      21              : #include <boost/mp11/integral.hpp>
      22              : #include <cmath>
      23              : #include <limits>
      24              : #include <cstring>
      25              : 
      26              : #ifdef _MSC_VER
      27              : #pragma warning(push)
      28              : #pragma warning(disable: 4702) // unreachable code
      29              : #pragma warning(disable: 4127) // conditional expression is constant
      30              : #endif
      31              : 
      32              : /*  This file must be manually included to get the
      33              :     function template definitions for basic_parser.
      34              : */
      35              : 
      36              : /*  Reference:
      37              : 
      38              :     https://www.json.org/
      39              : 
      40              :     RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
      41              :     https://tools.ietf.org/html/rfc7159
      42              : 
      43              :     https://ampl.com/netlib/fp/dtoa.c
      44              : */
      45              : 
      46              : #ifndef BOOST_JSON_DOCS
      47              : 
      48              : namespace boost {
      49              : namespace json {
      50              : namespace detail {
      51              : 
      52              : inline
      53              : double
      54      1033693 : pow10(int exp) noexcept
      55              : {
      56              :     static double const tab[618] = {
      57              :                         1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
      58              : 
      59              :         1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
      60              :         1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
      61              :         1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
      62              :         1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
      63              :         1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
      64              :         1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
      65              :         1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
      66              :         1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
      67              :         1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
      68              :         1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
      69              : 
      70              :         1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
      71              :         1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
      72              :         1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
      73              :         1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
      74              :         1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
      75              :         1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
      76              :         1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
      77              :         1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
      78              :         1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
      79              :         1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
      80              : 
      81              :         1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
      82              :         1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
      83              :         1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
      84              :         1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
      85              :         1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
      86              :         1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
      87              :         1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
      88              :         1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
      89              :         1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
      90              :         1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
      91              : 
      92              :         1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
      93              :         1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
      94              :         1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
      95              :         1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
      96              :         1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
      97              :         1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
      98              :         1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
      99              :         1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
     100              :         1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
     101              :         1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
     102              : 
     103              :         1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
     104              :         1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
     105              :         1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
     106              :         1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
     107              :         1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
     108              :         1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
     109              :         1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
     110              :         1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
     111              :         1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
     112              :         1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
     113              : 
     114              :         1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
     115              :         1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
     116              :         1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
     117              :         1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
     118              :         1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
     119              :         1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
     120              :         1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
     121              :         1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
     122              :         1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
     123              :         1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
     124              : 
     125              :         1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
     126              : 
     127      1033693 :     if( exp > 308 )
     128              :     {
     129          341 :         return std::numeric_limits<double>::infinity();
     130              :     }
     131      1033352 :     else if( exp < -308 )
     132              :     {
     133              :         // due to the way pow10 is used by dec_to_float,
     134              :         // we can afford to return 0.0 here
     135          151 :         return 0.0;
     136              :     }
     137              :     else
     138              :     {
     139      1033201 :         exp += 308;
     140      1033201 :         BOOST_ASSERT(exp >= 0 && exp < 618);
     141      1033201 :         return tab[exp];
     142              :     }
     143              : }
     144              : 
     145              : inline
     146              : double
     147      1033693 : dec_to_float(
     148              :     std::uint64_t m,
     149              :     std::int32_t e,
     150              :     bool neg) noexcept
     151              : {
     152              :     // convert to double explicitly to silence warnings
     153      1033693 :     double x = static_cast<double>(m);
     154      1033693 :     if(neg)
     155        13164 :         x = -x;
     156              : 
     157      1033693 :     if(e < -305)
     158              :     {
     159         5187 :         x *= 1e-305 ;
     160         5187 :         e += 305;
     161              :     }
     162              : 
     163      1033693 :     if(e >= -22 && e < 0)
     164        54813 :         return x / pow10(-e);
     165              : 
     166       978880 :     return x * pow10(e);
     167              : }
     168              : 
     169              : inline
     170              : bool
     171              : is_control(char c) noexcept
     172              : {
     173              :     return static_cast<unsigned char>(c) < 32;
     174              : }
     175              : 
     176              : inline
     177              : int
     178        66931 : hex_digit(unsigned char c) noexcept
     179              : {
     180              :     // by Peter Dimov
     181        66931 :     if( c >= '0' && c <= '9' )
     182        35759 :         return c - '0';
     183        31172 :     c &= ~0x20;
     184        31172 :     if( c >= 'A' && c <= 'F' )
     185        30562 :         return 10 + c - 'A';
     186          610 :     return -1;
     187              : }
     188              : 
     189              : enum json_literal
     190              : {
     191              :     null_literal = 0,
     192              :     true_literal,
     193              :     false_literal,
     194              :     infinity_literal,
     195              :     neg_infinity_literal,
     196              :     nan_literal,
     197              :     resume_literal = -1
     198              : };
     199              : 
     200              : } // detail
     201              : 
     202              : //----------------------------------------------------------
     203              : 
     204              : template< class Handler >
     205              : template< bool StackEmpty_, char First_ >
     206              : struct basic_parser<Handler>::
     207              : parse_number_helper
     208              : {
     209              :     basic_parser* parser;
     210              :     char const* p;
     211              : 
     212              :     template< std::size_t N >
     213              :     char const*
     214      2126839 :     operator()( mp11::mp_size_t<N> ) const
     215              :     {
     216      4248237 :         return parser->parse_number(
     217      2126839 :             p,
     218              :             std::integral_constant<bool, StackEmpty_>(),
     219              :             std::integral_constant<char, First_>(),
     220              :             std::integral_constant<
     221      2121399 :                 number_precision, static_cast<number_precision>(N)>() );
     222              :     }
     223              : };
     224              : 
     225              : //----------------------------------------------------------
     226              : 
     227              : template<class Handler>
     228              : void
     229       210492 : basic_parser<Handler>::
     230              : reserve()
     231              : {
     232       210492 :     if(BOOST_JSON_LIKELY(
     233              :         ! st_.empty()))
     234        37434 :         return;
     235              :     // Reserve the largest stack we need,
     236              :     // to avoid reallocation during suspend.
     237       346116 :     st_.reserve(
     238              :         sizeof(state) + // document parsing state
     239              :         (sizeof(state) +
     240       173058 :             sizeof(std::size_t)) * depth() + // array and object state + size
     241              :         sizeof(state) + // value parsing state
     242              :         sizeof(std::size_t) + // string size
     243              :         sizeof(state)); // comment state
     244              : }
     245              : 
     246              : //----------------------------------------------------------
     247              : //
     248              : // The sentinel value is returned by parse functions
     249              : // to indicate that the parser failed, or suspended.
     250              : // this is used as it is distinct from all valid values
     251              : // for data in write
     252              : 
     253              : template<class Handler>
     254              : const char*
     255      5340588 : basic_parser<Handler>::
     256              : sentinel()
     257              : {
     258              :     // the "+1" ensures that the returned pointer is unique even if
     259              :     // the given input buffer borders on this object
     260              :     return reinterpret_cast<
     261      5340588 :         const char*>(this) + 1;
     262              : }
     263              : 
     264              : template<class Handler>
     265              : bool
     266      2459737 : basic_parser<Handler>::
     267              : incomplete(
     268              :     const detail::const_stream_wrapper& cs)
     269              : {
     270      2459737 :     return cs.begin() == sentinel();
     271              : }
     272              : 
     273              : //----------------------------------------------------------
     274              : //
     275              : // These functions are declared with the BOOST_NOINLINE
     276              : // attribute to avoid polluting the parsers hot-path.
     277              : // They return the canary value to indicate suspension
     278              : // or failure.
     279              : 
     280              : template<class Handler>
     281              : const char*
     282              : basic_parser<Handler>::
     283              : suspend_or_fail(state st)
     284              : {
     285              :     if(BOOST_JSON_LIKELY(
     286              :         ! ec_ && more_))
     287              :     {
     288              :         // suspend
     289              :         reserve();
     290              :         st_.push_unchecked(st);
     291              :     }
     292              :     return sentinel();
     293              : }
     294              : 
     295              : template<class Handler>
     296              : const char*
     297        56132 : basic_parser<Handler>::
     298              : suspend_or_fail(
     299              :     state st,
     300              :     std::size_t n)
     301              : {
     302        56132 :     if(BOOST_JSON_LIKELY(
     303              :         ! ec_ && more_))
     304              :     {
     305              :         // suspend
     306        35826 :         reserve();
     307        35826 :         st_.push_unchecked(n);
     308        35826 :         st_.push_unchecked(st);
     309              :     }
     310        56132 :     return sentinel();
     311              : }
     312              : 
     313              : 
     314              : template<class Handler>
     315              : const char*
     316        18979 : basic_parser<Handler>::
     317              : fail(const char* p) noexcept
     318              : {
     319        18979 :     BOOST_ASSERT( p != sentinel() );
     320        18979 :     end_ = p;
     321        18979 :     return sentinel();
     322              : }
     323              : 
     324              : template<class Handler>
     325              : const char*
     326         7772 : basic_parser<Handler>::
     327              : fail(
     328              :     const char* p,
     329              :     error ev,
     330              :     source_location const* loc) noexcept
     331              : {
     332         7772 :     BOOST_ASSERT( p != sentinel() );
     333         7772 :     end_ = p;
     334         7772 :     ec_.assign(ev, loc);
     335         7772 :     return sentinel();
     336              : }
     337              : 
     338              : template<class Handler>
     339              : const char*
     340        11289 : basic_parser<Handler>::
     341              : maybe_suspend(
     342              :     const char* p,
     343              :     state st)
     344              : {
     345        11289 :     if( p != sentinel() )
     346         9424 :         end_ = p;
     347        11289 :     if(BOOST_JSON_LIKELY(more_))
     348              :     {
     349              :         // suspend
     350        11027 :         reserve();
     351        11027 :         st_.push_unchecked(st);
     352              :     }
     353        11289 :     return sentinel();
     354              : }
     355              : 
     356              : template<class Handler>
     357              : const char*
     358        38210 : basic_parser<Handler>::
     359              : maybe_suspend(
     360              :     const char* p,
     361              :     state st,
     362              :     std::size_t n)
     363              : {
     364        38210 :     BOOST_ASSERT( p != sentinel() );
     365        38210 :     end_ = p;
     366        38210 :     if(BOOST_JSON_LIKELY(more_))
     367              :     {
     368              :         // suspend
     369        37810 :         reserve();
     370        37810 :         st_.push_unchecked(n);
     371        37810 :         st_.push_unchecked(st);
     372              :     }
     373        38210 :     return sentinel();
     374              : }
     375              : 
     376              : template<class Handler>
     377              : const char*
     378         1123 : basic_parser<Handler>::
     379              : maybe_suspend(
     380              :     const char* p,
     381              :     state st,
     382              :     const number& num)
     383              : {
     384         1123 :     BOOST_ASSERT( p != sentinel() );
     385         1123 :     end_ = p;
     386         1123 :     if(BOOST_JSON_LIKELY(more_))
     387              :     {
     388              :         // suspend
     389         1123 :         num_ = num;
     390         1123 :         reserve();
     391         1123 :         st_.push_unchecked(st);;
     392              :     }
     393         1123 :     return sentinel();
     394              : }
     395              : 
     396              : template<class Handler>
     397              : const char*
     398        88657 : basic_parser<Handler>::
     399              : suspend(
     400              :     const char* p,
     401              :     state st)
     402              : {
     403        88657 :     BOOST_ASSERT( p != sentinel() );
     404        88657 :     end_ = p;
     405              :     // suspend
     406        88657 :     reserve();
     407        88657 :     st_.push_unchecked(st);
     408        88657 :     return sentinel();
     409              : }
     410              : 
     411              : template<class Handler>
     412              : const char*
     413        36049 : basic_parser<Handler>::
     414              : suspend(
     415              :     const char* p,
     416              :     state st,
     417              :     const number& num)
     418              : {
     419        36049 :     BOOST_ASSERT( p != sentinel() );
     420        36049 :     end_ = p;
     421              :     // suspend
     422        36049 :     num_ = num;
     423        36049 :     reserve();
     424        36049 :     st_.push_unchecked(st);
     425        36049 :     return sentinel();
     426              : }
     427              : 
     428              : template<class Handler>
     429              : template<
     430              :     bool StackEmpty_/*,
     431              :     bool Terminal_*/>
     432              : const char*
     433        21737 : basic_parser<Handler>::
     434              : parse_comment(const char* p,
     435              :     std::integral_constant<bool, StackEmpty_> stack_empty,
     436              :     /*std::integral_constant<bool, Terminal_>*/ bool terminal)
     437              : {
     438        21737 :     detail::const_stream_wrapper cs(p, end_);
     439        21737 :     const char* start = cs.begin();
     440              :     std::size_t remain;
     441        21737 :     if(! stack_empty && ! st_.empty())
     442              :     {
     443              :         state st;
     444         3507 :         st_.pop(st);
     445         3507 :         switch(st)
     446              :         {
     447            0 :             default: BOOST_JSON_UNREACHABLE();
     448          534 :             case state::com1: goto do_com1;
     449         2319 :             case state::com2: goto do_com2;
     450          438 :             case state::com3: goto do_com3;
     451          216 :             case state::com4: goto do_com4;
     452              :         }
     453              :     }
     454        18230 :     BOOST_ASSERT(*cs == '/');
     455        18230 :     ++cs;
     456        18764 : do_com1:
     457        18764 :     if(BOOST_JSON_UNLIKELY(! cs))
     458          551 :         return maybe_suspend(cs.begin(), state::com1);
     459        18213 :     switch(*cs)
     460              :     {
     461            5 :     default:
     462              :         {
     463              :             BOOST_STATIC_CONSTEXPR source_location loc
     464              :                 = BOOST_CURRENT_LOCATION;
     465            5 :             return fail(cs.begin(), error::syntax, &loc);
     466              :         }
     467        10524 :     case '/':
     468        10524 :         ++cs;
     469        12843 : do_com2:
     470              :         // KRYSTIAN TODO: this is a mess, we have to fix this
     471        12843 :         remain = cs.remain();
     472        25686 :         cs = remain ? static_cast<const char*>(
     473        12843 :             std::memchr(cs.begin(), '\n', remain)) : sentinel();
     474        12843 :         if(! cs.begin())
     475         2143 :             cs = sentinel();
     476        12843 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     477              :         {
     478              :             // if the doc does not terminate
     479              :             // with a newline, treat it as the
     480              :             // end of the comment
     481         2568 :             if(terminal && ! more_)
     482              :             {
     483           39 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment(
     484              :                     {start, cs.remain(start)}, ec_)))
     485            2 :                     return fail(cs.end());
     486           35 :                 return cs.end();
     487              :             }
     488         2529 :             if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     489              :                 {start, cs.remain(start)}, ec_)))
     490           95 :                 return fail(cs.end());
     491         2339 :             if(terminal)
     492          106 :                 return suspend(cs.end(), state::com2);
     493         2233 :             return maybe_suspend(cs.end(), state::com2);
     494              :         }
     495        10275 :         break;
     496         1684 :     case '*':
     497              :         do
     498              :         {
     499         9368 :             ++cs;
     500         9806 : do_com3:
     501              :             // KRYSTIAN TODO: this is a mess, we have to fix this
     502         9806 :             remain = cs.remain();
     503        19612 :             cs = remain ? static_cast<const char*>(
     504         9806 :                 std::memchr(cs.begin(), '*', remain)) : sentinel();
     505         9806 :             if(! cs.begin())
     506          242 :                 cs = sentinel();
     507              :             // stopped inside a c comment
     508         9806 :             if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     509              :             {
     510          503 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     511              :                     {start, cs.remain(start)}, ec_)))
     512           30 :                     return fail(cs.end());
     513          443 :                 return maybe_suspend(cs.end(), state::com3);
     514              :             }
     515              :             // found a asterisk, check if the next char is a slash
     516         9303 :             ++cs;
     517         9519 : do_com4:
     518         9519 :             if(BOOST_JSON_UNLIKELY(! cs))
     519              :             {
     520          259 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     521              :                     {start, cs.used(start)}, ec_)))
     522           18 :                     return fail(cs.begin());
     523          223 :                 return maybe_suspend(cs.begin(), state::com4);
     524              :             }
     525              :         }
     526         9260 :         while(*cs != '/');
     527              :     }
     528        17851 :     ++cs;
     529        17851 :     if(BOOST_JSON_UNLIKELY(! h_.on_comment(
     530              :         {start, cs.used(start)}, ec_)))
     531          964 :         return fail(cs.begin());
     532        15923 :     return cs.begin();
     533              : }
     534              : 
     535              : template<class Handler>
     536              : template<bool StackEmpty_>
     537              : const char*
     538      2318364 : basic_parser<Handler>::
     539              : parse_document(const char* p,
     540              :     std::integral_constant<bool, StackEmpty_> stack_empty)
     541              : {
     542      2318364 :     detail::const_stream_wrapper cs(p, end_);
     543      2318364 :     if(! stack_empty && ! st_.empty())
     544              :     {
     545              :         state st;
     546       169578 :         st_.peek(st);
     547       169578 :         switch(st)
     548              :         {
     549        83514 :         default: goto do_doc2;
     550          601 :         case state::doc1:
     551          601 :                  st_.pop(st);
     552          601 :                  goto do_doc1;
     553        85243 :         case state::doc3:
     554        85243 :                  st_.pop(st);
     555        85243 :                  goto do_doc3;
     556          220 :         case state::com1: case state::com2:
     557              :         case state::com3: case state::com4:
     558          220 :                  goto do_doc4;
     559              :         }
     560              :     }
     561      2148786 : do_doc1:
     562      2149387 :     cs = detail::count_whitespace(cs.begin(), cs.end());
     563      2149387 :     if(BOOST_JSON_UNLIKELY(! cs))
     564          633 :         return maybe_suspend(cs.begin(), state::doc1);
     565      2148754 : do_doc2:
     566      2232268 :     switch(+opt_.allow_comments |
     567      2232268 :         (opt_.allow_trailing_commas << 1) |
     568      2232268 :         (opt_.allow_invalid_utf8 << 2))
     569              :     {
     570              :     // no extensions
     571      2208603 :     default:
     572      2208603 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
     573      2193445 :         break;
     574              :     // comments
     575        13534 :     case 1:
     576        13534 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
     577        11271 :         break;
     578              :     // trailing
     579         6710 :     case 2:
     580         6710 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
     581         5117 :         break;
     582              :     // comments & trailing
     583          761 :     case 3:
     584          761 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
     585          761 :         break;
     586              :     // skip validation
     587          760 :     case 4:
     588          760 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
     589          760 :         break;
     590              :     // comments & skip validation
     591          760 :     case 5:
     592          760 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
     593          760 :         break;
     594              :     // trailing & skip validation
     595          760 :     case 6:
     596          760 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
     597          760 :         break;
     598              :     // comments & trailing & skip validation
     599          380 :     case 7:
     600          380 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
     601          380 :         break;
     602              :     }
     603      2213254 :     if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     604              :         // the appropriate state has already been pushed into stack
     605       110691 :         return sentinel();
     606      2102563 : do_doc3:
     607      2188138 :     cs = detail::count_whitespace(cs.begin(), cs.end());
     608      2188138 :     if(BOOST_JSON_UNLIKELY(! cs))
     609              :     {
     610      2185540 :         if(more_)
     611        88551 :             return suspend(cs.begin(), state::doc3);
     612              :     }
     613         2598 :     else if(opt_.allow_comments && *cs == '/')
     614              :     {
     615          536 : do_doc4:
     616          756 :         cs = parse_comment(cs.begin(), stack_empty, std::true_type());
     617          671 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     618          339 :             return sentinel();
     619          332 :         goto do_doc3;
     620              :     }
     621      2099051 :     return cs.begin();
     622              : }
     623              : 
     624              : template<class Handler>
     625              : template<
     626              :     bool StackEmpty_,
     627              :     bool AllowComments_/*,
     628              :     bool AllowTrailing_,
     629              :     bool AllowBadUTF8_*/>
     630              : const char*
     631      2349846 : basic_parser<Handler>::
     632              : parse_value(const char* p,
     633              :     std::integral_constant<bool, StackEmpty_> stack_empty,
     634              :     std::integral_constant<bool, AllowComments_> allow_comments,
     635              :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
     636              :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
     637              :     bool allow_bad_utf16)
     638              : {
     639      2349846 :     if(stack_empty || st_.empty())
     640              :     {
     641      2247970 : loop:
     642      2252886 :         switch(*p)
     643              :         {
     644        22753 :         case '0':
     645        22753 :             return mp11::mp_with_index<3>(
     646        22753 :                 static_cast<unsigned char>(opt_.numbers),
     647        22092 :                 parse_number_helper<true, '0'>{ this, p });
     648        25177 :         case '-':
     649        25177 :             return mp11::mp_with_index<3>(
     650        25177 :                 static_cast<unsigned char>(opt_.numbers),
     651        24065 :                 parse_number_helper<true, '-'>{ this, p });
     652      2041740 :         case '1': case '2': case '3':
     653              :         case '4': case '5': case '6':
     654              :         case '7': case '8': case '9':
     655      2041740 :             return mp11::mp_with_index<3>(
     656      2041740 :                 static_cast<unsigned char>(opt_.numbers),
     657      2038896 :                 parse_number_helper<true, '+'>{ this, p });
     658        11378 :         case 'n':
     659        11378 :             return parse_literal( p, mp11::mp_int<detail::null_literal>() );
     660          663 :         case 't':
     661          663 :             return parse_literal( p, mp11::mp_int<detail::true_literal>() );
     662          722 :         case 'f':
     663          722 :             return parse_literal( p, mp11::mp_int<detail::false_literal>() );
     664          681 :         case 'I':
     665          681 :             if( !opt_.allow_infinity_and_nan )
     666              :             {
     667              :                 BOOST_STATIC_CONSTEXPR source_location loc
     668              :                     = BOOST_CURRENT_LOCATION;
     669           24 :                 return fail(p, error::syntax, &loc);
     670              :             }
     671          657 :             return parse_literal( p, mp11::mp_int<detail::infinity_literal>() );
     672          231 :         case 'N':
     673          231 :             if( !opt_.allow_infinity_and_nan )
     674              :             {
     675              :                 BOOST_STATIC_CONSTEXPR source_location loc
     676              :                     = BOOST_CURRENT_LOCATION;
     677           30 :                 return fail(p, error::syntax, &loc);
     678              :             }
     679          201 :             return parse_literal( p, mp11::mp_int<detail::nan_literal>() );
     680        47571 :         case '"':
     681        47571 :             return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
     682        20605 :         case '[':
     683        20605 :             return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     684        74123 :         case '{':
     685        74123 :             return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     686         6125 :         case '/':
     687         6125 :             if(! allow_comments)
     688              :             {
     689              :                 BOOST_STATIC_CONSTEXPR source_location loc
     690              :                     = BOOST_CURRENT_LOCATION;
     691          284 :                 return fail(p, error::syntax, &loc);
     692              :             }
     693         5841 :             p = parse_comment(p, stack_empty, std::false_type());
     694              :             // KRYSTIAN NOTE: incomplete takes const_stream, we either
     695              :             // can add an overload, change the existing one to take a pointer,
     696              :             // or just leave it as is
     697         5605 :             if(BOOST_JSON_UNLIKELY(p == sentinel()))
     698          591 :                 return maybe_suspend(p, state::val2);
     699              :             // intentional fallthrough
     700              :         case ' ':
     701              :         case '\t':
     702              :         case '\n':
     703              :         case '\r':
     704         5026 :             p = detail::count_whitespace(p, end_);
     705         5026 :             if(BOOST_JSON_UNLIKELY(p == end_))
     706          110 :                 return maybe_suspend(p, state::val1);
     707         4916 :             goto loop;
     708         1105 :         default:
     709              :             {
     710              :                 BOOST_STATIC_CONSTEXPR source_location loc
     711              :                     = BOOST_CURRENT_LOCATION;
     712         1105 :                 return fail(p, error::syntax, &loc);
     713              :             }
     714              :         }
     715              :     }
     716       101876 :     return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     717              : }
     718              : 
     719              : template<class Handler>
     720              : template<
     721              :     bool AllowComments_/*,
     722              :     bool AllowTrailing_,
     723              :     bool AllowBadUTF8_*/>
     724              : const char*
     725       101876 : basic_parser<Handler>::
     726              : resume_value(const char* p,
     727              :     std::integral_constant<bool, AllowComments_> allow_comments,
     728              :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
     729              :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
     730              :     bool allow_bad_utf16)
     731              : {
     732              :     state st;
     733       101876 :     st_.peek(st);
     734       101876 :     switch(st)
     735              :     {
     736            0 :     default: BOOST_JSON_UNREACHABLE();
     737         1924 :     case state::lit1:
     738         1924 :         return parse_literal(p,  mp11::mp_int<detail::resume_literal>() );
     739              : 
     740        20256 :     case state::str1: case state::str2:
     741              :     case state::str8:
     742        20256 :         return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
     743              : 
     744         5705 :     case state::arr1: case state::arr2:
     745              :     case state::arr3: case state::arr4:
     746              :     case state::arr5: case state::arr6:
     747         5705 :         return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     748              : 
     749        35039 :     case state::obj1: case state::obj2:
     750              :     case state::obj3: case state::obj4:
     751              :     case state::obj5: case state::obj6:
     752              :     case state::obj7: case state::obj8:
     753              :     case state::obj9: case state::obj10:
     754              :     case state::obj11:
     755        35039 :         return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     756              : 
     757        37169 :     case state::num1: case state::num2:
     758              :     case state::num3: case state::num4:
     759              :     case state::num5: case state::num6:
     760              :     case state::num7: case state::num8:
     761              :     case state::exp1: case state::exp2:
     762              :     case state::exp3:
     763        37169 :         return mp11::mp_with_index<3>(
     764        37169 :             static_cast<unsigned char>(opt_.numbers),
     765        36346 :             parse_number_helper<false, 0>{ this, p });
     766              : 
     767              :     // KRYSTIAN NOTE: these are special cases
     768          108 :     case state::val1:
     769              :     {
     770          108 :         st_.pop(st);
     771          108 :         BOOST_ASSERT(st_.empty());
     772          108 :         p = detail::count_whitespace(p, end_);
     773          108 :         if(BOOST_JSON_UNLIKELY(p == end_))
     774            0 :             return maybe_suspend(p, state::val1);
     775          108 :         return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     776              :     }
     777              : 
     778         1608 :     case state::val2:
     779              :     {
     780         1608 :         st_.pop(st);
     781         1608 :         p = parse_comment(p, std::false_type(), std::false_type());
     782         1590 :         if(BOOST_JSON_UNLIKELY(p == sentinel()))
     783         1274 :             return maybe_suspend(p, state::val2);
     784          316 :         if(BOOST_JSON_UNLIKELY( p == end_ ))
     785           77 :             return maybe_suspend(p, state::val3);
     786          239 :         BOOST_ASSERT(st_.empty());
     787          239 :         return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
     788              :     }
     789              : 
     790           67 :     case state::val3:
     791              :     {
     792           67 :         st_.pop(st);
     793           67 :         return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
     794              :     }
     795              :     }
     796              : }
     797              : 
     798              : template<class Handler>
     799              : template<int Literal>
     800              : const char*
     801        16561 : basic_parser<Handler>::
     802              : parse_literal(const char* p,
     803              :     std::integral_constant<int, Literal> literal)
     804              : {
     805        16561 :     constexpr char const* literals[] = {
     806              :         "null",
     807              :         "true",
     808              :         "false",
     809              :         "Infinity",
     810              :         "-Infinity",
     811              :         "NaN",
     812              :     };
     813              : 
     814        16561 :     constexpr std::size_t literal_sizes[] = {
     815              :         4,
     816              :         4,
     817              :         5,
     818              :         8,
     819              :         9,
     820              :         3,
     821              :     };
     822              : 
     823              :     std::size_t cur_lit;
     824              :     std::size_t offset;
     825              : 
     826        16561 :     detail::const_stream_wrapper cs(p, end_);
     827        16561 :     BOOST_IF_CONSTEXPR( literal != detail::resume_literal )
     828              :     {
     829            0 :         BOOST_ASSERT( literal >= 0 );
     830        13630 :         if(BOOST_JSON_LIKELY( cs.remain() >= literal_sizes[literal] ))
     831              :         {
     832        11980 :             int const cmp = std::memcmp(
     833        11980 :                 cs.begin(), literals[literal], literal_sizes[literal] );
     834        11980 :             if( cmp != 0 )
     835              :             {
     836              :                 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     837          197 :                 return fail(cs.begin(), error::syntax, &loc);
     838              :             }
     839              : 
     840        11783 :             BOOST_IF_CONSTEXPR( literal == detail::null_literal )
     841              :             {
     842        10786 :                 if(BOOST_JSON_UNLIKELY(
     843              :                     ! h_.on_null(ec_)))
     844          160 :                     return fail(cs.begin());
     845              :             }
     846          997 :             else BOOST_IF_CONSTEXPR( literal == detail::true_literal )
     847              :             {
     848          383 :                 if(BOOST_JSON_UNLIKELY(
     849              :                     ! h_.on_bool(true, ec_)))
     850           13 :                     return fail(cs.begin());
     851              :             }
     852          614 :             else BOOST_IF_CONSTEXPR( literal == detail::false_literal )
     853              :             {
     854          406 :                 if(BOOST_JSON_UNLIKELY(
     855              :                     ! h_.on_bool(false, ec_)))
     856           13 :                     return fail(cs.begin());
     857              :             }
     858          208 :             else BOOST_IF_CONSTEXPR( literal == detail::infinity_literal )
     859              :             {
     860          103 :                 if(BOOST_JSON_UNLIKELY(
     861              :                     ! h_.on_double(
     862              :                         std::numeric_limits<double>::infinity(),
     863              :                         string_view(
     864              :                             literals[detail::infinity_literal],
     865              :                             literal_sizes[detail::infinity_literal]),
     866              :                         ec_)))
     867           13 :                     return fail(cs.begin());
     868              :             }
     869          105 :             else BOOST_IF_CONSTEXPR( literal == detail::neg_infinity_literal )
     870              :             {
     871            9 :                 if(BOOST_JSON_UNLIKELY(
     872              :                     ! h_.on_double(
     873              :                         -std::numeric_limits<double>::infinity(),
     874              :                         string_view(
     875              :                             literals[detail::neg_infinity_literal],
     876              :                             literal_sizes[detail::neg_infinity_literal]),
     877              :                         ec_)))
     878            1 :                     return fail(cs.begin());
     879              :             }
     880           96 :             else BOOST_IF_CONSTEXPR( literal == detail::nan_literal )
     881              :             {
     882           96 :                 if(BOOST_JSON_UNLIKELY(
     883              :                     ! h_.on_double(
     884              :                         std::numeric_limits<double>::quiet_NaN(),
     885              :                         string_view(
     886              :                             literals[detail::nan_literal],
     887              :                             literal_sizes[detail::nan_literal]),
     888              :                         ec_)))
     889           12 :                     return fail(cs.begin());
     890              :             }
     891              :             else
     892              :             {
     893            0 :                 BOOST_JSON_UNREACHABLE();
     894              :             }
     895              : 
     896        11361 :             cs += literal_sizes[literal];
     897        11361 :             return cs.begin();
     898              :         }
     899              : 
     900         1650 :         offset = 0;
     901         1650 :         cur_lit = literal;
     902              :     }
     903              :     else
     904              :     {
     905              :         state st;
     906         2931 :         st_.pop(st);
     907         2931 :         BOOST_ASSERT( st == state::lit1 );
     908              : 
     909         2931 :         cur_lit = cur_lit_;
     910         2931 :         offset = lit_offset_;
     911              :     }
     912              : 
     913         9162 :     std::size_t const size = (std::min)(
     914         4581 :         literal_sizes[cur_lit] - offset, cs.remain() );
     915         4581 :     int cmp = 0;
     916         4581 :     if(BOOST_JSON_LIKELY( cs.begin() ))
     917         4580 :         cmp = std::memcmp( cs.begin(), literals[cur_lit] + offset, size );
     918         4581 :     if( cmp != 0 )
     919              :     {
     920              :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     921          699 :         return fail(cs.begin(), error::syntax, &loc);
     922              :     }
     923              : 
     924         3882 :     if(BOOST_JSON_UNLIKELY( offset + size < literal_sizes[cur_lit] ))
     925              :     {
     926         1990 :         BOOST_ASSERT( cur_lit < 256 );
     927         1990 :         cur_lit_ = static_cast<unsigned char>( cur_lit );
     928         1990 :         BOOST_ASSERT( offset + size < 256 );
     929         1990 :         lit_offset_ = static_cast<unsigned char>( offset + size );
     930         1990 :         return maybe_suspend(cs.begin() + size, state::lit1);
     931              :     }
     932              : 
     933         1892 :     switch( cur_lit )
     934              :     {
     935          472 :     case detail::null_literal:
     936          472 :         if(BOOST_JSON_UNLIKELY(
     937              :             ! h_.on_null(ec_)))
     938           61 :             return fail(cs.begin());
     939          351 :         break;
     940          152 :     case detail::true_literal:
     941          152 :         if(BOOST_JSON_UNLIKELY(
     942              :             ! h_.on_bool(true, ec_)))
     943           22 :             return fail(cs.begin());
     944          109 :         break;
     945          198 :     case detail::false_literal:
     946          198 :         if(BOOST_JSON_UNLIKELY(
     947              :             ! h_.on_bool(false, ec_)))
     948           28 :             return fail(cs.begin());
     949          142 :         break;
     950          308 :     case detail::infinity_literal:
     951          308 :         if(BOOST_JSON_UNLIKELY(
     952              :             ! h_.on_double(
     953              :                 std::numeric_limits<double>::infinity(),
     954              :                 string_view(
     955              :                     literals[detail::infinity_literal],
     956              :                     literal_sizes[detail::infinity_literal]),
     957              :                 ec_)))
     958           49 :             return fail(cs.begin());
     959          210 :         break;
     960          686 :     case detail::neg_infinity_literal:
     961          686 :         if(BOOST_JSON_UNLIKELY(
     962              :             ! h_.on_double(
     963              :                 -std::numeric_limits<double>::infinity(),
     964              :                 string_view(
     965              :                     literals[detail::neg_infinity_literal],
     966              :                     literal_sizes[detail::neg_infinity_literal]),
     967              :                 ec_)))
     968          102 :             return fail(cs.begin());
     969          482 :         break;
     970           76 :     case detail::nan_literal:
     971           76 :         if(BOOST_JSON_UNLIKELY(
     972              :             ! h_.on_double(
     973              :                 std::numeric_limits<double>::quiet_NaN(),
     974              :                 string_view(
     975              :                     literals[detail::nan_literal],
     976              :                     literal_sizes[detail::nan_literal]),
     977              :                 ec_)))
     978           12 :             return fail(cs.begin());
     979           52 :         break;
     980            0 :     default: BOOST_JSON_UNREACHABLE();
     981              :     }
     982              : 
     983         1346 :     cs += size;
     984         1346 :     return cs.begin();
     985              : }
     986              : 
     987              : //----------------------------------------------------------
     988              : 
     989              : template<class Handler>
     990              : template<bool StackEmpty_, bool IsKey_>
     991              : const char*
     992       161284 : basic_parser<Handler>::
     993              : parse_string(const char* p,
     994              :     std::integral_constant<bool, StackEmpty_> stack_empty,
     995              :     std::integral_constant<bool, IsKey_> is_key,
     996              :     bool allow_bad_utf8,
     997              :     bool allow_bad_utf16)
     998              : {
     999       161284 :     detail::const_stream_wrapper cs(p, end_);
    1000              :     std::size_t total;
    1001              :     char const* start;
    1002              :     std::size_t size;
    1003       161284 :     if(! stack_empty && ! st_.empty())
    1004              :     {
    1005              :         state st;
    1006        32892 :         st_.pop(st);
    1007        32892 :         st_.pop(total);
    1008        32892 :         switch(st)
    1009              :         {
    1010            0 :         default: BOOST_JSON_UNREACHABLE();
    1011         3149 :         case state::str2: goto do_str2;
    1012         1861 :         case state::str8: goto do_str8;
    1013        27882 :         case state::str1: break;
    1014              :         }
    1015              :     }
    1016              :     else
    1017              :     {
    1018       128392 :         BOOST_ASSERT(*cs == '\x22'); // '"'
    1019       128392 :         ++cs;
    1020       128392 :         total = 0;
    1021              :     }
    1022              : 
    1023       164766 : do_str1:
    1024       164766 :     start = cs.begin();
    1025       329532 :     cs = allow_bad_utf8?
    1026         2177 :         detail::count_valid<true>(cs.begin(), cs.end()):
    1027       162589 :         detail::count_valid<false>(cs.begin(), cs.end());
    1028       164766 :     size = cs.used(start);
    1029       164766 :     if(is_key)
    1030              :     {
    1031        46677 :         BOOST_ASSERT(total <= Handler::max_key_size);
    1032        93988 :         if(BOOST_JSON_UNLIKELY(size >
    1033              :             Handler::max_key_size - total))
    1034              :         {
    1035              :             BOOST_STATIC_CONSTEXPR source_location loc
    1036              :                 = BOOST_CURRENT_LOCATION;
    1037            3 :             return fail(cs.begin(), error::key_too_large, &loc);
    1038              :         }
    1039              :     }
    1040              :     else
    1041              :     {
    1042        35316 :         BOOST_ASSERT(total <= Handler::max_string_size);
    1043        70778 :         if(BOOST_JSON_UNLIKELY(size >
    1044              :             Handler::max_string_size - total))
    1045              :         {
    1046              :             BOOST_STATIC_CONSTEXPR source_location loc
    1047              :                 = BOOST_CURRENT_LOCATION;
    1048            3 :             return fail(cs.begin(), error::string_too_large, &loc);
    1049              :         }
    1050              :     }
    1051       164760 :     total += size;
    1052       164760 :     if(BOOST_JSON_UNLIKELY(! cs))
    1053              :     {
    1054              :         // call handler if the string isn't empty
    1055        30216 :         if(BOOST_JSON_LIKELY(size))
    1056              :         {
    1057              :             {
    1058        27060 :                 bool r = is_key?
    1059        12399 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1060        15995 :                     h_.on_string_part( {start, size}, total, ec_ );
    1061              : 
    1062        25952 :                 if(BOOST_JSON_UNLIKELY(!r))
    1063              :                 {
    1064         1110 :                     return fail(cs.begin());
    1065              :                 }
    1066              :             }
    1067              :         }
    1068        27998 :         return maybe_suspend(cs.begin(), state::str1, total);
    1069              :     }
    1070              :     // at this point all valid characters have been skipped, so any remaining
    1071              :     // if there are any more characters, they are either escaped, or incomplete
    1072              :     // utf8, or invalid utf8
    1073       134544 :     if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
    1074              :     {
    1075              :         // sequence is invalid or incomplete
    1076        15068 :         if((*cs & 0x80) && !allow_bad_utf8)
    1077              :         {
    1078         3462 :             seq_.save(cs.begin(), cs.remain());
    1079         3462 :             if(BOOST_JSON_UNLIKELY(seq_.complete()))
    1080              :             {
    1081              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1082              :                     = BOOST_CURRENT_LOCATION;
    1083         1557 :                 return fail(cs.begin(), error::syntax, &loc);
    1084              :             }
    1085         1905 :             if(BOOST_JSON_LIKELY(size))
    1086              :             {
    1087          245 :                 bool const r = is_key?
    1088           22 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1089          245 :                     h_.on_string_part( {start, size}, total, ec_ );
    1090          223 :                 if(BOOST_JSON_UNLIKELY( !r ))
    1091           22 :                     return fail( cs.begin() );
    1092              :             }
    1093         1861 :             return maybe_suspend(cs.end(), state::str8, total);
    1094              :         }
    1095        11606 :         else if(BOOST_JSON_LIKELY(*cs == '\\'))
    1096              :         {
    1097              :             // flush unescaped run from input
    1098        11497 :             if(BOOST_JSON_LIKELY(size))
    1099              :             {
    1100         4250 :                 bool const r = is_key?
    1101         1226 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1102         3554 :                     h_.on_string_part( {start, size}, total, ec_ );
    1103         3766 :                 if(BOOST_JSON_UNLIKELY( !r ))
    1104          484 :                     return fail( cs.begin() );
    1105              :             }
    1106         7247 : do_str2:
    1107        13678 :             cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
    1108        12716 :             if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
    1109         5473 :                 return suspend_or_fail(state::str2, total);
    1110              : 
    1111         7243 :             goto do_str1;
    1112              :         }
    1113              :         // illegal control
    1114              :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1115          109 :         return fail(cs.begin(), error::syntax, &loc);
    1116              :     }
    1117              : 
    1118              :     {
    1119       119476 :         bool r = is_key?
    1120        84505 :             h_.on_key( {start, size}, total, ec_ ):
    1121        41980 :             h_.on_string( {start, size}, total, ec_ );
    1122              : 
    1123       115102 :         if(BOOST_JSON_UNLIKELY(!r))
    1124              :         {
    1125         4313 :             return fail(cs.begin());
    1126              :         }
    1127              :     }
    1128              : 
    1129       110789 :     ++cs;
    1130       110789 :     return cs.begin();
    1131              : 
    1132         1861 : do_str8:
    1133         1861 :     uint8_t needed = seq_.needed();
    1134         1861 :     if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
    1135            0 :         return maybe_suspend(cs.end(), state::str8, total);
    1136         1861 :     if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
    1137              :     {
    1138              :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1139          210 :         return fail(cs.begin(), error::syntax, &loc);
    1140              :     }
    1141              :     {
    1142         1651 :         bool const r = is_key?
    1143          201 :             h_.on_key_part( {seq_.data(), seq_.length()}, total, ec_ ):
    1144         1651 :             h_.on_string_part( {seq_.data(), seq_.length()}, total, ec_ );
    1145         1450 :         if(BOOST_JSON_UNLIKELY( !r ))
    1146          201 :             return fail( cs.begin() );
    1147              :     }
    1148         1249 :     cs += needed;
    1149         1249 :     goto do_str1;
    1150              : }
    1151              : 
    1152              : template<class Handler>
    1153              : template<bool StackEmpty_>
    1154              : const char*
    1155        13678 : basic_parser<Handler>::
    1156              : parse_escaped(
    1157              :     const char* p,
    1158              :     std::size_t& total,
    1159              :     std::integral_constant<bool, StackEmpty_> stack_empty,
    1160              :     bool is_key,
    1161              :     bool allow_bad_utf16)
    1162              : {
    1163        13678 :     constexpr unsigned urc = 0xFFFD; // Unicode replacement character
    1164        13678 :     auto const ev_too_large = is_key?
    1165              :         error::key_too_large : error::string_too_large;
    1166        13678 :     auto const max_size = is_key?
    1167              :         Handler::max_key_size : Handler::max_string_size;
    1168              :     int digit;
    1169              : 
    1170              :     //---------------------------------------------------------------
    1171              :     //
    1172              :     // To handle escapes, a local temporary buffer accumulates
    1173              :     // the unescaped result. The algorithm attempts to fill the
    1174              :     // buffer to capacity before invoking the handler.
    1175              :     // In some cases the temporary buffer needs to be flushed
    1176              :     // before it is full:
    1177              :     // * When the closing double quote is seen
    1178              :     // * When there in no more input (and more is expected later)
    1179              :     // A goal of the algorithm is to call the handler as few times
    1180              :     // as possible. Thus, when the first escape is encountered,
    1181              :     // the algorithm attempts to fill the temporary buffer first.
    1182              :     //
    1183        13678 :     detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
    1184              : 
    1185              :     // Unescaped JSON is never larger than its escaped version.
    1186              :     // To efficiently process only what will fit in the temporary buffer,
    1187              :     // the size of the input stream is temporarily "clipped" to the size
    1188              :     // of the temporary buffer.
    1189              :     // handle escaped character
    1190        13678 :     detail::clipped_const_stream cs(p, end_);
    1191        13678 :     cs.clip(temp.max_size());
    1192              : 
    1193        13678 :     if(! stack_empty && ! st_.empty())
    1194              :     {
    1195              :         state st;
    1196         3149 :         st_.pop(st);
    1197         3149 :         switch(st)
    1198              :         {
    1199            0 :         default: BOOST_JSON_UNREACHABLE();
    1200          528 :         case state::str3: goto do_str3;
    1201          392 :         case state::str4: goto do_str4;
    1202          390 :         case state::str5: goto do_str5;
    1203          389 :         case state::str6: goto do_str6;
    1204          386 :         case state::str7: goto do_str7;
    1205          232 :         case state::sur1: goto do_sur1;
    1206          188 :         case state::sur2: goto do_sur2;
    1207          164 :         case state::sur3: goto do_sur3;
    1208          162 :         case state::sur4: goto do_sur4;
    1209          160 :         case state::sur5: goto do_sur5;
    1210          158 :         case state::sur6: goto do_sur6;
    1211              :         }
    1212              :     }
    1213              : 
    1214         3781 :     while(true)
    1215              :     {
    1216        14310 :         BOOST_ASSERT( temp.capacity() );
    1217        14310 :         BOOST_ASSERT(*cs == '\\');
    1218        14310 :         ++cs;
    1219        15169 : do_str3:
    1220        15374 :         if(BOOST_JSON_UNLIKELY(! cs))
    1221              :         {
    1222          561 :             if(BOOST_JSON_LIKELY(! temp.empty()))
    1223              :             {
    1224            0 :                 BOOST_ASSERT(total <= max_size);
    1225          100 :                 if(BOOST_JSON_UNLIKELY(
    1226              :                     temp.size() > max_size - total))
    1227              :                 {
    1228              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1229              :                         = BOOST_CURRENT_LOCATION;
    1230            0 :                     return fail(cs.begin(), ev_too_large, &loc);
    1231              :                 }
    1232          100 :                 total += temp.size();
    1233              :                 {
    1234           91 :                     bool r = is_key
    1235          100 :                         ? h_.on_key_part(temp.get(), total, ec_)
    1236          100 :                         : h_.on_string_part(temp.get(), total, ec_);
    1237              : 
    1238           91 :                     if(BOOST_JSON_UNLIKELY(!r))
    1239              :                     {
    1240            9 :                         return fail(cs.begin());
    1241              :                     }
    1242              :                 }
    1243           82 :                 temp.clear();
    1244              :             }
    1245          543 :             cs.clip(temp.max_size());
    1246          543 :             if(BOOST_JSON_UNLIKELY(! cs))
    1247          543 :                 return maybe_suspend(cs.begin(), state::str3);
    1248              :         }
    1249        14813 :         switch(*cs)
    1250              :         {
    1251          191 :         default:
    1252              :             {
    1253              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1254              :                     = BOOST_CURRENT_LOCATION;
    1255          191 :                 return fail(cs.begin(), error::syntax, &loc);
    1256              :             }
    1257          265 :         case '\x22': // '"'
    1258          265 :             temp.push_back('\x22');
    1259          265 :             ++cs;
    1260          265 :             break;
    1261          178 :         case '\\':
    1262          178 :             temp.push_back('\\');
    1263          178 :             ++cs;
    1264          178 :             break;
    1265           96 :         case '/':
    1266           96 :             temp.push_back('/');
    1267           96 :             ++cs;
    1268           96 :             break;
    1269          112 :         case 'b':
    1270          112 :             temp.push_back('\x08');
    1271          112 :             ++cs;
    1272          112 :             break;
    1273          108 :         case 'f':
    1274          108 :             temp.push_back('\x0c');
    1275          108 :             ++cs;
    1276          108 :             break;
    1277         1763 :         case 'n':
    1278         1763 :             temp.push_back('\x0a');
    1279         1763 :             ++cs;
    1280         1763 :             break;
    1281          146 :         case 'r':
    1282          146 :             temp.push_back('\x0d');
    1283          146 :             ++cs;
    1284          146 :             break;
    1285          266 :         case 't':
    1286          266 :             temp.push_back('\x09');
    1287          266 :             ++cs;
    1288          266 :             break;
    1289        11688 :         case 'u':
    1290              :             // utf16 escape
    1291              :             //
    1292              :             // fast path only when the buffer
    1293              :             // is large enough for 2 surrogates
    1294        11688 :             if(BOOST_JSON_LIKELY(cs.remain() > 10))
    1295              :             {
    1296              :                 // KRYSTIAN TODO: this could be done
    1297              :                 // with fewer instructions
    1298        11394 :                 digit = detail::load_little_endian<4>(
    1299         5697 :                     cs.begin() + 1);
    1300         5697 :                 int d4 = detail::hex_digit(static_cast<
    1301         5697 :                     unsigned char>(digit >> 24));
    1302         5697 :                 int d3 = detail::hex_digit(static_cast<
    1303         5697 :                     unsigned char>(digit >> 16));
    1304         5697 :                 int d2 = detail::hex_digit(static_cast<
    1305         5697 :                     unsigned char>(digit >> 8));
    1306         5697 :                 int d1 = detail::hex_digit(static_cast<
    1307              :                     unsigned char>(digit));
    1308         5697 :                 if(BOOST_JSON_UNLIKELY(
    1309              :                     (d1 | d2 | d3 | d4) == -1))
    1310              :                 {
    1311           60 :                     if(d1 != -1)
    1312           45 :                         ++cs;
    1313           60 :                     if(d2 != -1)
    1314           30 :                         ++cs;
    1315           60 :                     if(d3 != -1)
    1316           15 :                         ++cs;
    1317              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1318              :                         = BOOST_CURRENT_LOCATION;
    1319           60 :                     return fail(cs.begin(), error::expected_hex_digit, &loc);
    1320              :                 }
    1321              :                 // 32 bit unicode scalar value
    1322         5637 :                 unsigned u1 =
    1323         5637 :                     (d1 << 12) + (d2 << 8) +
    1324         5637 :                     (d3 << 4) + d4;
    1325              :                 // valid unicode scalar values are
    1326              :                 // [0, D7FF] and [E000, 10FFFF]
    1327              :                 // values within this range are valid utf-8
    1328              :                 // code points and invalid leading surrogates.
    1329         5637 :                 if(BOOST_JSON_LIKELY(
    1330              :                     u1 < 0xd800 || u1 > 0xdfff))
    1331              :                 {
    1332         1340 :                     cs += 5;
    1333         1340 :                     temp.append_utf8(u1);
    1334         1340 :                     break;
    1335              :                 }
    1336         4297 :                 if(BOOST_JSON_UNLIKELY(u1 > 0xdbff))
    1337              :                 {
    1338              :                     // If it's an illegal leading surrogate and
    1339              :                     // the parser does not allow it, return an error.
    1340          707 :                     if(!allow_bad_utf16)
    1341              :                     {
    1342              :                         BOOST_STATIC_CONSTEXPR source_location loc
    1343              :                             = BOOST_CURRENT_LOCATION;
    1344          122 :                         return fail(cs.begin(), error::illegal_leading_surrogate,
    1345          122 :                             &loc);
    1346              :                     }
    1347              :                     // Otherwise, append the Unicode replacement character
    1348              :                     else
    1349              :                     {
    1350          585 :                         cs += 5;
    1351          585 :                         temp.append_utf8(urc);
    1352          585 :                         break;
    1353              :                     }
    1354              :                 }
    1355         3590 :                 cs += 5;
    1356              :                 // KRYSTIAN TODO: this can be a two byte load
    1357              :                 // and a single comparison. We lose error information,
    1358              :                 // but it's faster.
    1359         3590 :                 if(BOOST_JSON_UNLIKELY(*cs != '\\'))
    1360              :                 {
    1361              :                     // If the next character is not a backslash and
    1362              :                     // the parser does not allow it, return a syntax error.
    1363          156 :                     if(!allow_bad_utf16)
    1364              :                     {
    1365              :                         BOOST_STATIC_CONSTEXPR source_location loc
    1366              :                             = BOOST_CURRENT_LOCATION;
    1367           15 :                         return fail(cs.begin(), error::syntax, &loc);
    1368              :                     }
    1369              :                     // Otherwise, append the Unicode replacement character since
    1370              :                     // the first code point is a valid leading surrogate
    1371              :                     else
    1372              :                     {
    1373          141 :                         temp.append_utf8(urc);
    1374          141 :                         break;
    1375              :                     }
    1376              :                 }
    1377         3434 :                 ++cs;
    1378         3434 :                 if(BOOST_JSON_UNLIKELY(*cs != 'u'))
    1379              :                 {
    1380          220 :                     if (!allow_bad_utf16)
    1381              :                     {
    1382              :                         BOOST_STATIC_CONSTEXPR source_location loc
    1383              :                             = BOOST_CURRENT_LOCATION;
    1384           15 :                         return fail(cs.begin(), error::syntax, &loc);
    1385              :                     }
    1386              :                     // Otherwise, append the Unicode replacement character since
    1387              :                     // the first code point is a valid leading surrogate
    1388              :                     else
    1389              :                     {
    1390          205 :                         temp.append_utf8(urc);
    1391          205 :                         goto do_str3;
    1392              :                     }
    1393              :                 }
    1394         3214 :                 ++cs;
    1395         3214 :                 digit = detail::load_little_endian<4>(cs.begin());
    1396         3214 :                 d4 = detail::hex_digit(static_cast<
    1397         3214 :                     unsigned char>(digit >> 24));
    1398         3214 :                 d3 = detail::hex_digit(static_cast<
    1399         3214 :                     unsigned char>(digit >> 16));
    1400         3214 :                 d2 = detail::hex_digit(static_cast<
    1401         3214 :                     unsigned char>(digit >> 8));
    1402         3214 :                 d1 = detail::hex_digit(static_cast<
    1403              :                     unsigned char>(digit));
    1404         3214 :                 if(BOOST_JSON_UNLIKELY(
    1405              :                     (d1 | d2 | d3 | d4) == -1))
    1406              :                 {
    1407           90 :                     if(d1 != -1)
    1408           75 :                         ++cs;
    1409           90 :                     if(d2 != -1)
    1410           45 :                         ++cs;
    1411           90 :                     if(d3 != -1)
    1412           15 :                         ++cs;
    1413              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1414              :                         = BOOST_CURRENT_LOCATION;
    1415           90 :                     return fail(cs.begin(), error::expected_hex_digit, &loc);
    1416              :                 }
    1417         3124 :                 unsigned u2 =
    1418         3124 :                     (d1 << 12) + (d2 << 8) +
    1419         3124 :                     (d3 << 4) + d4;
    1420              :                 // Check if the second code point is a valid trailing surrogate.
    1421              :                 // Valid trailing surrogates are [DC00, DFFF]
    1422         3124 :                 if(BOOST_JSON_UNLIKELY(
    1423              :                     u2 < 0xdc00 || u2 > 0xdfff))
    1424              :                 {
    1425              :                     // If not valid and the parser does not allow it, return an error.
    1426         1353 :                     if(!allow_bad_utf16)
    1427              :                     {
    1428              :                         BOOST_STATIC_CONSTEXPR source_location loc
    1429              :                             = BOOST_CURRENT_LOCATION;
    1430          136 :                         return fail(cs.begin(), error::illegal_trailing_surrogate,
    1431          136 :                             &loc);
    1432              :                     }
    1433              :                     // Append the replacement character for the
    1434              :                     // first leading surrogate.
    1435         1217 :                     cs += 4;
    1436         1217 :                     temp.append_utf8(urc);
    1437              :                     // Check if the second code point is a
    1438              :                     // valid unicode scalar value (invalid leading
    1439              :                     // or trailing surrogate)
    1440         1217 :                     if (u2 < 0xd800 || u2 > 0xdbff)
    1441              :                     {
    1442          524 :                         temp.append_utf8(u2);
    1443          524 :                         break;
    1444              :                     }
    1445              :                     // If it is a valid leading surrogate
    1446              :                     else
    1447              :                     {
    1448          693 :                         u1_ = u2;
    1449          693 :                         goto do_sur1;
    1450              :                     }
    1451              :                 }
    1452         1771 :                 cs += 4;
    1453              :                 // Calculate the Unicode code point from the surrogate pair and
    1454              :                 // append the UTF-8 representation.
    1455         1771 :                 unsigned cp =
    1456         1771 :                     ((u1 - 0xd800) << 10) +
    1457              :                     ((u2 - 0xdc00)) +
    1458              :                         0x10000;
    1459              :                 // utf-16 surrogate pair
    1460         1771 :                 temp.append_utf8(cp);
    1461         1771 :                 break;
    1462              :             }
    1463              :             // flush
    1464         5991 :             if(BOOST_JSON_LIKELY(! temp.empty()))
    1465              :             {
    1466            3 :                 BOOST_ASSERT(total <= max_size);
    1467         1722 :                 if(BOOST_JSON_UNLIKELY(
    1468              :                     temp.size() > max_size - total))
    1469              :                 {
    1470              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1471              :                         = BOOST_CURRENT_LOCATION;
    1472            0 :                     return fail(cs.begin(), ev_too_large, &loc);
    1473              :                 }
    1474         1722 :                 total += temp.size();
    1475              :                 {
    1476         1582 :                     bool r = is_key
    1477         1722 :                         ? h_.on_key_part(temp.get(), total, ec_)
    1478         1722 :                         : h_.on_string_part(temp.get(), total, ec_);
    1479              : 
    1480         1582 :                     if(BOOST_JSON_UNLIKELY(!r))
    1481              :                     {
    1482          140 :                         return fail(cs.begin());
    1483              :                     }
    1484              :                 }
    1485         1442 :                 temp.clear();
    1486         1442 :                 cs.clip(temp.max_size());
    1487              :             }
    1488         5711 :             ++cs;
    1489              :             // utf-16 escape
    1490         6103 :     do_str4:
    1491         6103 :             if(BOOST_JSON_UNLIKELY(! cs))
    1492          392 :                 return maybe_suspend(cs.begin(), state::str4);
    1493         5711 :             digit = detail::hex_digit(*cs);
    1494         5711 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1495              :             {
    1496              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1497              :                     = BOOST_CURRENT_LOCATION;
    1498           50 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1499              :             }
    1500         5661 :             ++cs;
    1501         5661 :             u1_ = digit << 12;
    1502         6051 :     do_str5:
    1503         6051 :             if(BOOST_JSON_UNLIKELY(! cs))
    1504          390 :                 return maybe_suspend(cs.begin(), state::str5);
    1505         5661 :             digit = detail::hex_digit(*cs);
    1506         5661 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1507              :             {
    1508              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1509              :                     = BOOST_CURRENT_LOCATION;
    1510           20 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1511              :             }
    1512         5641 :             ++cs;
    1513         5641 :             u1_ += digit << 8;
    1514         6030 :     do_str6:
    1515         6030 :             if(BOOST_JSON_UNLIKELY(! cs))
    1516          389 :                 return maybe_suspend(cs.begin(), state::str6);
    1517         5641 :             digit = detail::hex_digit(*cs);
    1518         5641 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1519              :             {
    1520              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1521              :                     = BOOST_CURRENT_LOCATION;
    1522           20 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1523              :             }
    1524         5621 :             ++cs;
    1525         5621 :             u1_ += digit << 4;
    1526         6007 :     do_str7:
    1527         6007 :             if(BOOST_JSON_UNLIKELY(! cs))
    1528          386 :                 return maybe_suspend(cs.begin(), state::str7);
    1529         5621 :             digit = detail::hex_digit(*cs);
    1530         5621 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1531              :             {
    1532              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1533              :                     = BOOST_CURRENT_LOCATION;
    1534           35 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1535              :             }
    1536         5586 :             ++cs;
    1537         5586 :             u1_ += digit;
    1538         5586 :             if(BOOST_JSON_LIKELY(
    1539              :                 u1_ < 0xd800 || u1_ > 0xdfff))
    1540              :             {
    1541         1434 :                 BOOST_ASSERT(temp.empty());
    1542              :                 // utf-8 codepoint
    1543         1434 :                 temp.append_utf8(u1_);
    1544         1434 :                 break;
    1545              :             }
    1546         4152 :             if(BOOST_JSON_UNLIKELY(u1_ > 0xdbff))
    1547              :             {
    1548              :                 // If it's an illegal leading surrogate and
    1549              :                 // the parser does not allow it, return an error.
    1550         1585 :                 if(!allow_bad_utf16)
    1551              :                 {
    1552              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1553              :                         = BOOST_CURRENT_LOCATION;
    1554          209 :                     return fail(cs.begin(), error::illegal_leading_surrogate, &loc);
    1555              :                 }
    1556              :                 // Otherwise, append the Unicode replacement character
    1557              :                 else
    1558              :                 {
    1559         1376 :                     BOOST_ASSERT(temp.empty());
    1560         1376 :                     temp.append_utf8(urc);
    1561         1376 :                     break;
    1562              :                 }
    1563              :             }
    1564         2567 :     do_sur1:
    1565         3792 :             if(BOOST_JSON_UNLIKELY(! cs))
    1566          232 :                 return maybe_suspend(cs.begin(), state::sur1);
    1567         3560 :             if(BOOST_JSON_UNLIKELY(*cs != '\\'))
    1568              :             {
    1569              :                 // If the next character is not a backslash and
    1570              :                 // the parser does not allow it, return a syntax error.
    1571          952 :                 if(!allow_bad_utf16)
    1572              :                 {
    1573              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1574              :                         = BOOST_CURRENT_LOCATION;
    1575          149 :                     return fail(cs.begin(), error::syntax, &loc);
    1576              :                 }
    1577              :                 // Otherwise, append the Unicode replacement character since
    1578              :                 // the first code point is a valid leading surrogate
    1579              :                 else
    1580              :                 {
    1581          803 :                     temp.append_utf8(urc);
    1582          803 :                     break;
    1583              :                 }
    1584              :             }
    1585         2608 :             ++cs;
    1586         2796 :     do_sur2:
    1587         2796 :             if(BOOST_JSON_UNLIKELY(! cs))
    1588          188 :                 return maybe_suspend(cs.begin(), state::sur2);
    1589         2608 :             if(BOOST_JSON_UNLIKELY(*cs != 'u'))
    1590              :             {
    1591          396 :                 if (!allow_bad_utf16)
    1592              :                 {
    1593              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1594              :                         = BOOST_CURRENT_LOCATION;
    1595           65 :                     return fail(cs.begin(), error::syntax, &loc);
    1596              :                 }
    1597              :                 // Otherwise, append the Unicode replacement character since
    1598              :                 // the first code point is a valid leading surrogate
    1599              :                 else
    1600              :                 {
    1601          331 :                     temp.append_utf8(urc);
    1602          331 :                     goto do_str3;
    1603              :                 }
    1604              :             }
    1605         2212 :             ++cs;
    1606         2376 :     do_sur3:
    1607         2376 :             if(BOOST_JSON_UNLIKELY(! cs))
    1608          164 :                 return maybe_suspend(cs.begin(), state::sur3);
    1609         2212 :             digit = detail::hex_digit(*cs);
    1610         2212 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1611              :             {
    1612              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1613              :                     = BOOST_CURRENT_LOCATION;
    1614           35 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1615              :             }
    1616         2177 :             ++cs;
    1617         2177 :             u2_ = digit << 12;
    1618         2339 :     do_sur4:
    1619         2339 :             if(BOOST_JSON_UNLIKELY(! cs))
    1620          162 :                 return maybe_suspend(cs.begin(), state::sur4);
    1621         2177 :             digit = detail::hex_digit(*cs);
    1622         2177 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1623              :             {
    1624              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1625              :                     = BOOST_CURRENT_LOCATION;
    1626           35 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1627              :             }
    1628         2142 :             ++cs;
    1629         2142 :             u2_ += digit << 8;
    1630         2302 :     do_sur5:
    1631         2302 :             if(BOOST_JSON_UNLIKELY(! cs))
    1632          160 :                 return maybe_suspend(cs.begin(), state::sur5);
    1633         2142 :             digit = detail::hex_digit(*cs);
    1634         2142 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1635              :             {
    1636              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1637              :                     = BOOST_CURRENT_LOCATION;
    1638           20 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1639              :             }
    1640         2122 :             ++cs;
    1641         2122 :             u2_ += digit << 4;
    1642         2280 :     do_sur6:
    1643         2280 :             if(BOOST_JSON_UNLIKELY(! cs))
    1644          158 :                 return maybe_suspend(cs.begin(), state::sur6);
    1645         2122 :             digit = detail::hex_digit(*cs);
    1646         2122 :             if(BOOST_JSON_UNLIKELY(digit == -1))
    1647              :             {
    1648              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1649              :                     = BOOST_CURRENT_LOCATION;
    1650           20 :                 return fail(cs.begin(), error::expected_hex_digit, &loc);
    1651              :             }
    1652         2102 :             ++cs;
    1653         2102 :             u2_ += digit;
    1654              :             // Check if the second code point is a valid trailing surrogate.
    1655              :             // Valid trailing surrogates are [DC00, DFFF]
    1656         2102 :             if(BOOST_JSON_UNLIKELY(
    1657              :                 u2_ < 0xdc00 || u2_ > 0xdfff))
    1658              :             {
    1659              :                 // If not valid and the parser does not allow it, return an error.
    1660          580 :                 if(!allow_bad_utf16)
    1661              :                 {
    1662              :                     BOOST_STATIC_CONSTEXPR source_location loc
    1663              :                         = BOOST_CURRENT_LOCATION;
    1664           60 :                     return fail(cs.begin(), error::illegal_trailing_surrogate, &loc);
    1665              :                 }
    1666              :                 // Append the replacement character for the
    1667              :                 // first leading surrogate.
    1668          520 :                 temp.append_utf8(urc);
    1669              :                 // Check if the second code point is a
    1670              :                 // valid unicode scalar value (invalid leading
    1671              :                 // or trailing surrogate)
    1672          520 :                 if (u2_ < 0xd800 || u2_ > 0xdbff)
    1673              :                 {
    1674          220 :                     temp.append_utf8(u2_);
    1675          220 :                     break;
    1676              :                 }
    1677              :                 // If it is a valid leading surrogate
    1678              :                 else
    1679              :                 {
    1680          300 :                     u1_ = u2_;
    1681          300 :                     goto do_sur1;
    1682              :                 }
    1683              :             }
    1684              :             // Calculate the Unicode code point from the surrogate pair and
    1685              :             // append the UTF-8 representation.
    1686         1522 :             unsigned cp =
    1687         1522 :                 ((u1_ - 0xd800) << 10) +
    1688         1522 :                 ((u2_ - 0xdc00)) +
    1689              :                     0x10000;
    1690              :             // utf-16 surrogate pair
    1691         1522 :             temp.append_utf8(cp);
    1692              :         }
    1693              : 
    1694              :         // flush
    1695        12650 :         if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
    1696         8869 :             break;
    1697              :     }
    1698              : 
    1699         8869 :     if(BOOST_JSON_LIKELY( temp.size() ))
    1700              :     {
    1701          433 :         BOOST_ASSERT(total <= max_size);
    1702         8869 :         if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
    1703              :         {
    1704              :             BOOST_STATIC_CONSTEXPR source_location loc
    1705              :                 = BOOST_CURRENT_LOCATION;
    1706            0 :             return fail(cs.begin(), ev_too_large, &loc);
    1707              :         }
    1708              : 
    1709         8869 :         total += temp.size();
    1710         8056 :         bool const r = is_key
    1711         8869 :             ? h_.on_key_part(temp.get(), total, ec_)
    1712         8152 :             : h_.on_string_part(temp.get(), total, ec_);
    1713         8056 :         if(BOOST_JSON_UNLIKELY( !r ))
    1714          813 :             return fail( cs.begin() );
    1715              :     }
    1716              : 
    1717         7243 :     return cs.begin();
    1718              : }
    1719              : 
    1720              : //----------------------------------------------------------
    1721              : 
    1722              : template<class Handler>
    1723              : template<
    1724              :     bool StackEmpty_,
    1725              :     bool AllowComments_/*,
    1726              :     bool AllowTrailing_,
    1727              :     bool AllowBadUTF8_*/>
    1728              : const char*
    1729       109162 : basic_parser<Handler>::
    1730              : parse_object(const char* p,
    1731              :     std::integral_constant<bool, StackEmpty_> stack_empty,
    1732              :     std::integral_constant<bool, AllowComments_> allow_comments,
    1733              :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
    1734              :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
    1735              :     bool allow_bad_utf16)
    1736              : {
    1737       109162 :     detail::const_stream_wrapper cs(p, end_);
    1738              :     std::size_t size;
    1739       109162 :     if(! stack_empty && ! st_.empty())
    1740              :     {
    1741              :         // resume
    1742              :         state st;
    1743        35039 :         st_.pop(st);
    1744        35039 :         st_.pop(size);
    1745        35039 :         switch(st)
    1746              :         {
    1747            0 :         default: BOOST_JSON_UNREACHABLE();
    1748         1594 :         case state::obj1: goto do_obj1;
    1749          235 :         case state::obj2: goto do_obj2;
    1750        12636 :         case state::obj3: goto do_obj3;
    1751         1689 :         case state::obj4: goto do_obj4;
    1752          251 :         case state::obj5: goto do_obj5;
    1753         1590 :         case state::obj6: goto do_obj6;
    1754        15443 :         case state::obj7: goto do_obj7;
    1755          426 :         case state::obj8: goto do_obj8;
    1756          660 :         case state::obj9: goto do_obj9;
    1757          181 :         case state::obj10: goto do_obj10;
    1758          334 :         case state::obj11: goto do_obj11;
    1759              :         }
    1760              :     }
    1761        74123 :     BOOST_ASSERT(*cs == '{');
    1762        74123 :     size = 0;
    1763        74123 :     if(BOOST_JSON_UNLIKELY(! depth_))
    1764              :     {
    1765              :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1766            3 :         return fail(cs.begin(), error::too_deep, &loc);
    1767              :     }
    1768        74120 :     --depth_;
    1769        74120 :     if(BOOST_JSON_UNLIKELY(
    1770              :         ! h_.on_object_begin(ec_)))
    1771         2039 :         return fail(cs.begin());
    1772        70043 :     ++cs;
    1773              :     // object:
    1774              :     //     '{' *ws '}'
    1775              :     //     '{' *ws string *ws ':' *ws value *ws *[ ',' *ws string *ws ':' *ws value *ws ] '}'
    1776        73608 : do_obj1:
    1777        73608 :     cs = detail::count_whitespace(cs.begin(), cs.end());
    1778        73608 :     if(BOOST_JSON_UNLIKELY(! cs))
    1779         1628 :         return maybe_suspend(cs.begin(), state::obj1, size);
    1780        71980 :     if(BOOST_JSON_LIKELY(*cs != '}'))
    1781              :     {
    1782        69082 :         if(BOOST_JSON_UNLIKELY(*cs != '\x22'))
    1783              :         {
    1784         2411 :             if(allow_comments && *cs == '/')
    1785              :             {
    1786         2139 : do_obj2:
    1787         2374 :                 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1788         2290 :                 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1789          319 :                     return suspend_or_fail(state::obj2, size);
    1790         1971 :                 goto do_obj1;
    1791              :             }
    1792              :             BOOST_STATIC_CONSTEXPR source_location loc
    1793              :                 = BOOST_CURRENT_LOCATION;
    1794          272 :             return fail(cs.begin(), error::syntax, &loc);
    1795              :         }
    1796        66671 : loop:
    1797        80822 :         if(BOOST_JSON_UNLIKELY(++size >
    1798              :             Handler::max_object_size))
    1799              :         {
    1800              :             BOOST_STATIC_CONSTEXPR source_location loc
    1801              :                 = BOOST_CURRENT_LOCATION;
    1802            1 :             return fail(cs.begin(), error::object_too_large, &loc);
    1803              :         }
    1804        80821 : do_obj3:
    1805        93457 :         cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
    1806        90501 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1807        15580 :             return suspend_or_fail(state::obj3, size);
    1808        74921 : do_obj4:
    1809        79081 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1810        79081 :         if(BOOST_JSON_UNLIKELY(! cs))
    1811         1704 :             return maybe_suspend(cs.begin(), state::obj4, size);
    1812        77377 :         if(BOOST_JSON_UNLIKELY(*cs != ':'))
    1813              :         {
    1814         2925 :             if(allow_comments && *cs == '/')
    1815              :             {
    1816         2779 : do_obj5:
    1817         3030 :                 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1818         2876 :                 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1819          405 :                     return suspend_or_fail(state::obj5, size);
    1820         2471 :                 goto do_obj4;
    1821              :             }
    1822              :             BOOST_STATIC_CONSTEXPR source_location loc
    1823              :                 = BOOST_CURRENT_LOCATION;
    1824          146 :             return fail(cs.begin(), error::syntax, &loc);
    1825              :         }
    1826        74452 :         ++cs;
    1827        76042 : do_obj6:
    1828        76042 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1829        76042 :         if(BOOST_JSON_UNLIKELY(! cs))
    1830         1620 :             return maybe_suspend(cs.begin(), state::obj6, size);
    1831        74422 : do_obj7:
    1832        89865 :         cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
    1833        82516 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1834        23585 :             return suspend_or_fail(state::obj7, size);
    1835        58931 : do_obj8:
    1836        61193 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1837        61193 :         if(BOOST_JSON_UNLIKELY(! cs))
    1838          441 :             return maybe_suspend(cs.begin(), state::obj8, size);
    1839        60752 :         if(BOOST_JSON_LIKELY(*cs == ','))
    1840              :         {
    1841        17791 :             ++cs;
    1842        19706 : do_obj9:
    1843        19706 :             cs = detail::count_whitespace(cs.begin(), cs.end());
    1844        19706 :             if(BOOST_JSON_UNLIKELY(! cs))
    1845          690 :                 return maybe_suspend(cs.begin(), state::obj9, size);
    1846              : 
    1847              :             // loop for next element
    1848        19016 :             if(BOOST_JSON_LIKELY(*cs == '\x22'))
    1849        14151 :                 goto loop;
    1850         4865 :             if(! allow_trailing || *cs != '}')
    1851              :             {
    1852         1644 :                 if(allow_comments && *cs == '/')
    1853              :                 {
    1854         1433 : do_obj10:
    1855         1614 :                     cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1856         1525 :                     if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1857          270 :                         return suspend_or_fail(state::obj10, size);
    1858         1255 :                     goto do_obj9;
    1859              :                 }
    1860              :                 BOOST_STATIC_CONSTEXPR source_location loc
    1861              :                     = BOOST_CURRENT_LOCATION;
    1862          211 :                 return fail(cs.begin(), error::syntax, &loc);
    1863              :             }
    1864              :         }
    1865        42961 :         else if(BOOST_JSON_UNLIKELY(*cs != '}'))
    1866              :         {
    1867         2325 :             if(allow_comments && *cs == '/')
    1868              :             {
    1869         2172 : do_obj11:
    1870         2506 :                 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1871         2338 :                 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1872          502 :                     return suspend_or_fail(state::obj11, size);
    1873         1836 :                 goto do_obj8;
    1874              :             }
    1875              :             BOOST_STATIC_CONSTEXPR source_location loc
    1876              :                 = BOOST_CURRENT_LOCATION;
    1877          153 :             return fail(cs.begin(), error::syntax, &loc);
    1878              :         }
    1879              :         // got closing brace, fall through
    1880              :     }
    1881        46755 :     if(BOOST_JSON_UNLIKELY(
    1882              :         ! h_.on_object_end(size, ec_)))
    1883         1502 :         return fail(cs.begin());
    1884        43712 :     ++depth_;
    1885        43712 :     ++cs;
    1886        43712 :     return cs.begin();
    1887              : }
    1888              : 
    1889              : //----------------------------------------------------------
    1890              : 
    1891              : template<class Handler>
    1892              : template<
    1893              :     bool StackEmpty_,
    1894              :     bool AllowComments_/*,
    1895              :     bool AllowTrailing_,
    1896              :     bool AllowBadUTF8_*/>
    1897              : const char*
    1898        26310 : basic_parser<Handler>::
    1899              : parse_array(const char* p,
    1900              :     std::integral_constant<bool, StackEmpty_> stack_empty,
    1901              :     std::integral_constant<bool, AllowComments_> allow_comments,
    1902              :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
    1903              :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
    1904              :     bool allow_bad_utf16)
    1905              : {
    1906        26310 :     detail::const_stream_wrapper cs(p, end_);
    1907              :     std::size_t size;
    1908        26310 :     if(! stack_empty && ! st_.empty())
    1909              :     {
    1910              :         // resume
    1911              :         state st;
    1912         5705 :         st_.pop(st);
    1913         5705 :         st_.pop(size);
    1914         5705 :         switch(st)
    1915              :         {
    1916            0 :         default: BOOST_JSON_UNREACHABLE();
    1917         1050 :         case state::arr1: goto do_arr1;
    1918          384 :         case state::arr2: goto do_arr2;
    1919         2919 :         case state::arr3: goto do_arr3;
    1920          391 :         case state::arr4: goto do_arr4;
    1921          667 :         case state::arr5: goto do_arr5;
    1922          294 :         case state::arr6: goto do_arr6;
    1923              :         }
    1924              :     }
    1925        20605 :     BOOST_ASSERT(*cs == '[');
    1926        20605 :     size = 0;
    1927        20605 :     if(BOOST_JSON_UNLIKELY(! depth_))
    1928              :     {
    1929              :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1930           34 :         return fail(cs.begin(), error::too_deep, &loc);
    1931              :     }
    1932        20571 :     --depth_;
    1933        20571 :     if(BOOST_JSON_UNLIKELY(
    1934              :         ! h_.on_array_begin(ec_)))
    1935          809 :         return fail(cs.begin());
    1936        18956 :     ++cs;
    1937              :     // array:
    1938              :     //     '[' *ws ']'
    1939              :     //     '[' *ws value *ws *[ ',' *ws value *ws ] ']'
    1940        21539 : do_arr1:
    1941        21539 :     cs = detail::count_whitespace(cs.begin(), cs.end());
    1942        21539 :     if(BOOST_JSON_UNLIKELY(! cs))
    1943         1071 :         return maybe_suspend(cs.begin(), state::arr1, size);
    1944        20468 :     if(BOOST_JSON_LIKELY(*cs != ']'))
    1945              :     {
    1946        18722 : loop:
    1947        26170 :         if(allow_comments && *cs == '/')
    1948              :         {
    1949         1789 : do_arr2:
    1950         2173 :             cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1951         2045 :             if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1952          512 :                 return suspend_or_fail(state::arr2, size);
    1953         1533 :             goto do_arr1;
    1954              :         }
    1955        24381 :         if(BOOST_JSON_UNLIKELY(++size >
    1956              :             Handler::max_array_size))
    1957              :         {
    1958              :             BOOST_STATIC_CONSTEXPR source_location loc
    1959              :                 = BOOST_CURRENT_LOCATION;
    1960            1 :             return fail(cs.begin(), error::array_too_large, &loc);
    1961              :         }
    1962        24380 : do_arr3:
    1963              :         // array is not empty, value required
    1964        27299 :         cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
    1965        24668 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1966         9028 :             return suspend_or_fail(state::arr3, size);
    1967        15640 : do_arr4:
    1968        17261 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1969        17261 :         if(BOOST_JSON_UNLIKELY(! cs))
    1970          500 :             return maybe_suspend(cs.begin(), state::arr4, size);
    1971        16761 :         if(BOOST_JSON_LIKELY(*cs == ','))
    1972              :         {
    1973         9161 :             ++cs;
    1974         9828 : do_arr5:
    1975         9828 :             cs = detail::count_whitespace(cs.begin(), cs.end());
    1976         9828 :             if(BOOST_JSON_UNLIKELY(! cs))
    1977          697 :                 return maybe_suspend(cs.begin(), state::arr5, size);
    1978              :             // loop for next element
    1979         9131 :             if(! allow_trailing || *cs != ']')
    1980         7448 :                 goto loop;
    1981              :         }
    1982         7600 :         else if(BOOST_JSON_UNLIKELY(*cs != ']'))
    1983              :         {
    1984         1969 :             if(allow_comments && *cs == '/')
    1985              :             {
    1986         1541 : do_arr6:
    1987         1835 :                 cs = parse_comment(cs.begin(), stack_empty, std::false_type());
    1988         1688 :                 if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1989          458 :                     return suspend_or_fail(state::arr6, size);
    1990         1230 :                 goto do_arr4;
    1991              :             }
    1992              :             BOOST_STATIC_CONSTEXPR source_location loc
    1993              :                 = BOOST_CURRENT_LOCATION;
    1994          428 :             return fail(cs.begin(), error::syntax, &loc);
    1995              :         }
    1996              :         // got closing bracket; fall through
    1997              :     }
    1998         9060 :     if(BOOST_JSON_UNLIKELY(
    1999              :         ! h_.on_array_end(size, ec_)))
    2000          542 :         return fail(cs.begin());
    2001         7939 :     ++depth_;
    2002         7939 :     ++cs;
    2003         7939 :     return cs.begin();
    2004              : }
    2005              : 
    2006              : //----------------------------------------------------------
    2007              : 
    2008              : template<class Handler>
    2009              : template<bool StackEmpty_, char First_, number_precision Numbers_>
    2010              : const char*
    2011      2126839 : basic_parser<Handler>::
    2012              : parse_number(const char* p,
    2013              :     std::integral_constant<bool, StackEmpty_> stack_empty,
    2014              :     std::integral_constant<char, First_> first,
    2015              :     std::integral_constant<number_precision, Numbers_> mode)
    2016              : {
    2017      2126839 :     constexpr bool precise_parsing = mode == number_precision::precise;
    2018      2126839 :     constexpr bool no_parsing = mode == number_precision::none;
    2019              : 
    2020              :     // only one of these will be true if we are not resuming
    2021              :     // if negative then !zero_first && !nonzero_first
    2022              :     // if zero_first then !nonzero_first && !negative
    2023              :     // if nonzero_first then !zero_first && !negative
    2024      2126839 :     bool const negative = first == '-';
    2025      2126839 :     bool const zero_first = first == '0';
    2026      2126839 :     bool const nonzero_first = first == '+';
    2027      2126839 :     detail::const_stream_wrapper cs(p, end_);
    2028              :     number num;
    2029      2126839 :     const char* begin = cs.begin();
    2030      2126839 :     if(stack_empty || st_.empty())
    2031              :     {
    2032      2089670 :         num.bias = 0;
    2033      2089670 :         num.exp = 0;
    2034      2089670 :         num.frac = false;
    2035      2089670 :         num_buf_.clear();
    2036              : 
    2037              :         //----------------------------------
    2038              :         //
    2039              :         // '-'
    2040              :         // leading minus sign
    2041              :         //
    2042      2089670 :         BOOST_ASSERT(cs);
    2043              :         if(negative)
    2044        25177 :             ++cs;
    2045              : 
    2046      2089670 :         num.neg = negative;
    2047      2089670 :         num.frac = false;
    2048      2089670 :         num.exp = 0;
    2049      2089670 :         num.bias = 0;
    2050              : 
    2051              :         // fast path
    2052      2089670 :         if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
    2053              :         {
    2054              :             int n1;
    2055              : 
    2056         9988 :             if( nonzero_first ||
    2057         9988 :                 (negative && *cs != '0') )
    2058              :             {
    2059      2007317 :                 n1 = detail::count_digits( cs.begin() );
    2060      2007317 :                 BOOST_ASSERT(n1 >= 0 && n1 <= 16);
    2061              : 
    2062         1836 :                 if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
    2063              :                 {
    2064            9 :                     return parse_literal(
    2065            8 :                         p - 1, mp11::mp_int<detail::neg_infinity_literal>());
    2066              :                 }
    2067              : 
    2068         1827 :                 if( ! nonzero_first && n1 == 0 )
    2069              :                 {
    2070              :                     // digit required
    2071              :                     BOOST_STATIC_CONSTEXPR source_location loc
    2072              :                         = BOOST_CURRENT_LOCATION;
    2073            2 :                     return fail(cs.begin(), error::syntax, &loc);
    2074              :                 }
    2075              : 
    2076              :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2077      2006458 :                     num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
    2078              :                 else
    2079          848 :                     num.mant = 0;
    2080              : 
    2081      2007306 :                 cs += n1;
    2082              : 
    2083              :                 // integer or floating-point with
    2084              :                 // >= 16 leading digits
    2085      2007306 :                 if( n1 == 16 )
    2086              :                 {
    2087      2001424 :                     goto do_num2;
    2088              :                 }
    2089              :             }
    2090              :             else
    2091              :             {
    2092              :                 // 0. floating-point or 0e integer
    2093        21187 :                 num.mant = 0;
    2094        21187 :                 n1 = 0;
    2095        21187 :                 ++cs;
    2096              :             }
    2097              : 
    2098              :             {
    2099        27069 :                 const char c = *cs;
    2100        27069 :                 if(c != '.')
    2101              :                 {
    2102         9870 :                     if((c | 32) == 'e')
    2103              :                     {
    2104         6576 :                         ++cs;
    2105         6576 :                         goto do_exp1;
    2106              :                     }
    2107              :                     BOOST_IF_CONSTEXPR( negative && !no_parsing )
    2108           19 :                         num.mant = ~num.mant + 1;
    2109         3294 :                     goto finish_signed;
    2110              :                 }
    2111              :             }
    2112              : 
    2113              :             // floating-point number
    2114              : 
    2115        17199 :             ++cs;
    2116              : 
    2117        17199 :             int n2 = detail::count_digits( cs.begin() );
    2118        17199 :             BOOST_ASSERT(n2 >= 0 && n2 <= 16);
    2119              : 
    2120        17199 :             if( n2 == 0 )
    2121              :             {
    2122              :                 // digit required
    2123              :                 BOOST_STATIC_CONSTEXPR source_location loc
    2124              :                     = BOOST_CURRENT_LOCATION;
    2125            3 :                 return fail(cs.begin(), error::syntax, &loc);
    2126              :             }
    2127              : 
    2128              :             // floating-point mantissa overflow
    2129        17196 :             if( n1 + n2 >= 19 )
    2130              :             {
    2131          122 :                 goto do_num7;
    2132              :             }
    2133              : 
    2134              :             BOOST_IF_CONSTEXPR( !no_parsing )
    2135        12855 :                 num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
    2136              : 
    2137        17074 :             BOOST_ASSERT(num.bias == 0);
    2138              : 
    2139        17074 :             num.bias -= n2;
    2140              : 
    2141        17074 :             cs += n2;
    2142              : 
    2143        17074 :             char ch = *cs;
    2144              : 
    2145        17074 :             if( (ch | 32) == 'e' )
    2146              :             {
    2147          110 :                 ++cs;
    2148          110 :                 goto do_exp1;
    2149              :             }
    2150        16964 :             else if( ch >= '0' && ch <= '9' )
    2151              :             {
    2152        10017 :                 goto do_num8;
    2153              :             }
    2154              : 
    2155         6947 :             goto finish_dub;
    2156              :         }
    2157              :     }
    2158              :     else
    2159              :     {
    2160        37169 :         num = num_;
    2161              :         state st;
    2162        37169 :         st_.pop(st);
    2163        37169 :         switch(st)
    2164              :         {
    2165            0 :         default: BOOST_JSON_UNREACHABLE();
    2166          602 :         case state::num1: goto do_num1;
    2167         6333 :         case state::num2: goto do_num2;
    2168          802 :         case state::num3: goto do_num3;
    2169           52 :         case state::num4: goto do_num4;
    2170         4537 :         case state::num5: goto do_num5;
    2171          666 :         case state::num6: goto do_num6;
    2172          616 :         case state::num7: goto do_num7;
    2173        10944 :         case state::num8: goto do_num8;
    2174          469 :         case state::exp1: goto do_exp1;
    2175          125 :         case state::exp2: goto do_exp2;
    2176        12023 :         case state::exp3: goto do_exp3;
    2177              :         }
    2178              :     }
    2179              : 
    2180              :     //----------------------------------
    2181              :     //
    2182              :     // DIGIT
    2183              :     // first digit
    2184              :     //
    2185        61768 : do_num1:
    2186        15791 :     if(zero_first || nonzero_first ||
    2187        15791 :         BOOST_JSON_LIKELY(cs))
    2188              :     {
    2189        61046 :         char const c = *cs;
    2190              :         if(zero_first)
    2191              :         {
    2192         9718 :             ++cs;
    2193         9718 :             num.mant = 0;
    2194         9718 :             goto do_num6;
    2195              :         }
    2196        15069 :         else if(nonzero_first || BOOST_JSON_LIKELY(
    2197              :             c >= '1' && c <= '9'))
    2198              :         {
    2199        42506 :             ++cs;
    2200        42506 :             num.mant = c - '0';
    2201              :         }
    2202         8822 :         else if(BOOST_JSON_UNLIKELY(
    2203              :             c == '0'))
    2204              :         {
    2205         7627 :             ++cs;
    2206         7627 :             num.mant = 0;
    2207         7627 :             goto do_num6;
    2208              :         }
    2209         1195 :         else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
    2210              :         {
    2211         1007 :             st_.push(state::lit1);
    2212         1007 :             cur_lit_ = detail::neg_infinity_literal;
    2213         1007 :             lit_offset_ = 1;
    2214         1007 :             return parse_literal(
    2215          961 :                 cs.begin(), mp11::mp_int<detail::resume_literal>() );
    2216              :         }
    2217              :         else
    2218              :         {
    2219              :             BOOST_STATIC_CONSTEXPR source_location loc
    2220              :                 = BOOST_CURRENT_LOCATION;
    2221          188 :             return fail(cs.begin(), error::syntax, &loc);
    2222              :         }
    2223              :     }
    2224              :     else
    2225              :     {
    2226          722 :         if(BOOST_JSON_UNLIKELY(
    2227              :             ! h_.on_number_part(
    2228              :                 {begin, cs.used(begin)}, ec_)))
    2229           60 :             return fail(cs.begin());
    2230              : 
    2231              :         BOOST_IF_CONSTEXPR( precise_parsing )
    2232           64 :             num_buf_.append( begin, cs.used(begin) );
    2233          602 :         return maybe_suspend(
    2234          602 :             cs.begin(), state::num1, num);
    2235              :     }
    2236              : 
    2237              :     //----------------------------------
    2238              :     //
    2239              :     // 1*DIGIT
    2240              :     // significant digits left of decimal
    2241              :     //
    2242      2050263 : do_num2:
    2243      2044005 :     if(negative || (!stack_empty && num.neg))
    2244              :     {
    2245        22382 :         for(;;)
    2246              :         {
    2247        30207 :             if(BOOST_JSON_UNLIKELY(! cs))
    2248              :             {
    2249         1920 :                 if(BOOST_JSON_UNLIKELY(more_))
    2250              :                 {
    2251         1469 :                     if(BOOST_JSON_UNLIKELY(
    2252              :                         ! h_.on_number_part(
    2253              :                             {begin, cs.used(begin)}, ec_)))
    2254           69 :                         return fail(cs.begin());
    2255              : 
    2256              :                     BOOST_IF_CONSTEXPR( precise_parsing )
    2257           32 :                         num_buf_.append( begin, cs.used(begin) );
    2258         1331 :                     return suspend(cs.begin(), state::num2, num);
    2259              :                 }
    2260          451 :                 goto finish_int;
    2261              :             }
    2262        28287 :             char const c = *cs;
    2263        28287 :             if(BOOST_JSON_LIKELY(
    2264              :                 c >= '0' && c <= '9'))
    2265              :             {
    2266        23205 :                 ++cs;
    2267              :                 //              9223372036854775808 INT64_MIN
    2268        23205 :                 if( num.mant  > 922337203685477580 || (
    2269        22490 :                     num.mant == 922337203685477580 && c > '8'))
    2270              :                     break;
    2271              :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2272        22123 :                     num.mant = 10 * num.mant + ( c - '0' );
    2273        22382 :                 continue;
    2274              :             }
    2275         5082 :             goto do_num6; // [.eE]
    2276              :         }
    2277              :     }
    2278              :     else
    2279              :     {
    2280      6884997 :         for(;;)
    2281              :         {
    2282      8927435 :             if(BOOST_JSON_UNLIKELY(! cs))
    2283              :             {
    2284         6416 :                 if(BOOST_JSON_UNLIKELY(more_))
    2285              :                 {
    2286         5808 :                     if(BOOST_JSON_UNLIKELY(
    2287              :                         ! h_.on_number_part(
    2288              :                             {begin, cs.used(begin)}, ec_)))
    2289          406 :                         return fail(cs.begin());
    2290              : 
    2291              :                     BOOST_IF_CONSTEXPR( precise_parsing )
    2292          174 :                         num_buf_.append( begin, cs.used(begin) );
    2293         5002 :                     return suspend(cs.begin(), state::num2, num);
    2294              :                 }
    2295          608 :                 goto finish_int;
    2296              :             }
    2297      8921019 :             char const c = *cs;
    2298      8921019 :             if(BOOST_JSON_LIKELY(
    2299              :                 c >= '0' && c <= '9'))
    2300              :             {
    2301      6888822 :                 ++cs;
    2302              :                 //              18446744073709551615 UINT64_MAX
    2303      6888822 :                 if( num.mant  > 1844674407370955161 || (
    2304      6885419 :                     num.mant == 1844674407370955161 && c > '5'))
    2305              :                     break;
    2306              :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2307      6879399 :                     num.mant = 10 * num.mant + ( c - '0' );
    2308              :             }
    2309              :             else
    2310              :             {
    2311      2032197 :                 goto do_num6; // [.eE]
    2312              :             }
    2313              :         }
    2314              :     }
    2315         4648 :     ++num.bias;
    2316              : 
    2317              :     //----------------------------------
    2318              :     //
    2319              :     // 1*DIGIT
    2320              :     // non-significant digits left of decimal
    2321              :     //
    2322         5450 : do_num3:
    2323        11558 :     for(;;)
    2324              :     {
    2325        17008 :         if(BOOST_JSON_UNLIKELY(! cs))
    2326              :         {
    2327         1527 :             if(BOOST_JSON_UNLIKELY(more_))
    2328              :             {
    2329          894 :                 if(BOOST_JSON_UNLIKELY(
    2330              :                     ! h_.on_number_part(
    2331              :                         {begin, cs.used(begin)}, ec_)))
    2332           46 :                     return fail(cs.begin());
    2333              : 
    2334              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2335           12 :                     num_buf_.append( begin, cs.used(begin) );
    2336          802 :                 return suspend(cs.begin(), state::num3, num);
    2337              :             }
    2338          633 :             goto finish_dub;
    2339              :         }
    2340        15481 :         char const c = *cs;
    2341        15481 :         if(BOOST_JSON_UNLIKELY(
    2342              :             c >= '0' && c <= '9'))
    2343              :         {
    2344        11558 :             if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
    2345              :             {
    2346              :                 BOOST_STATIC_CONSTEXPR source_location loc
    2347              :                     = BOOST_CURRENT_LOCATION;
    2348            0 :                 return fail(cs.begin(), error::exponent_overflow, &loc);
    2349              :             }
    2350        11558 :             ++cs;
    2351        11558 :             ++num.bias;
    2352              :         }
    2353         3923 :         else if(BOOST_JSON_LIKELY(
    2354              :             c == '.'))
    2355              :         {
    2356         2028 :             ++cs;
    2357         2028 :             break;
    2358              :         }
    2359         1895 :         else if((c | 32) == 'e')
    2360              :         {
    2361          546 :             ++cs;
    2362          546 :             goto do_exp1;
    2363              :         }
    2364              :         else
    2365              :         {
    2366         1349 :             goto finish_dub;
    2367              :         }
    2368              :     }
    2369              : 
    2370              :     //----------------------------------
    2371              :     //
    2372              :     // DIGIT
    2373              :     // first non-significant digit
    2374              :     // to the right of decimal
    2375              :     //
    2376         2080 : do_num4:
    2377              :     {
    2378         2080 :         if(BOOST_JSON_UNLIKELY(! cs))
    2379              :         {
    2380           64 :             if(BOOST_JSON_UNLIKELY(
    2381              :                 ! h_.on_number_part(
    2382              :                     {begin, cs.used(begin)}, ec_)))
    2383            6 :                 return fail(cs.begin());
    2384              : 
    2385              :             BOOST_IF_CONSTEXPR( precise_parsing )
    2386            4 :                 num_buf_.append( begin, cs.used(begin) );
    2387           52 :             return maybe_suspend(
    2388           52 :                 cs.begin(), state::num4, num);
    2389              :         }
    2390         2016 :         char const c = *cs;
    2391         2016 :         if(BOOST_JSON_LIKELY(
    2392              :             //static_cast<unsigned char>(c - '0') < 10))
    2393              :             c >= '0' && c <= '9'))
    2394              :         {
    2395         1949 :             ++cs;
    2396              :         }
    2397              :         else
    2398              :         {
    2399              :             // digit required
    2400              :             BOOST_STATIC_CONSTEXPR source_location loc
    2401              :                 = BOOST_CURRENT_LOCATION;
    2402           67 :             return fail(cs.begin(), error::syntax, &loc);
    2403              :         }
    2404              :     }
    2405              : 
    2406              :     //----------------------------------
    2407              :     //
    2408              :     // 1*DIGIT
    2409              :     // non-significant digits
    2410              :     // to the right of decimal
    2411              :     //
    2412      2013470 : do_num5:
    2413     37889832 :     for(;;)
    2414              :     {
    2415     39903302 :         if(BOOST_JSON_UNLIKELY(! cs))
    2416              :         {
    2417         6112 :             if(BOOST_JSON_UNLIKELY(more_))
    2418              :             {
    2419         4577 :                 if(BOOST_JSON_UNLIKELY(
    2420              :                     ! h_.on_number_part(
    2421              :                         {begin, cs.used(begin)}, ec_)))
    2422           20 :                     return fail(cs.begin());
    2423              : 
    2424              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2425          178 :                     num_buf_.append( begin, cs.used(begin) );
    2426         4537 :                 return suspend(cs.begin(), state::num5, num);
    2427              :             }
    2428         1535 :             goto finish_dub;
    2429              :         }
    2430     39897190 :         char const c = *cs;
    2431     39897190 :         if(BOOST_JSON_LIKELY(
    2432              :             c >= '0' && c <= '9'))
    2433              :         {
    2434     37889832 :             ++cs;
    2435              :         }
    2436      2007358 :         else if((c | 32) == 'e')
    2437              :         {
    2438      2003236 :             ++cs;
    2439      2003236 :             goto do_exp1;
    2440              :         }
    2441              :         else
    2442              :         {
    2443         4122 :             goto finish_dub;
    2444              :         }
    2445              :     }
    2446              : 
    2447              :     //----------------------------------
    2448              :     //
    2449              :     // [.eE]
    2450              :     //
    2451      2055290 : do_num6:
    2452              :     {
    2453      2055290 :         if(BOOST_JSON_UNLIKELY(! cs))
    2454              :         {
    2455          798 :             if(BOOST_JSON_UNLIKELY(more_))
    2456              :             {
    2457          751 :                 if(BOOST_JSON_UNLIKELY(
    2458              :                     ! h_.on_number_part(
    2459              :                         {begin, cs.used(begin)}, ec_)))
    2460           42 :                     return fail(cs.begin());
    2461              : 
    2462              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2463           98 :                     num_buf_.append( begin, cs.used(begin) );
    2464          667 :                 return suspend(cs.begin(), state::num6, num);
    2465              :             }
    2466           47 :             goto finish_int;
    2467              :         }
    2468      2054492 :         char const c = *cs;
    2469      2054492 :         if(BOOST_JSON_LIKELY(
    2470              :             c == '.'))
    2471              :         {
    2472      2016097 :             ++cs;
    2473              :         }
    2474        38395 :         else if((c | 32) == 'e')
    2475              :         {
    2476         9140 :             ++cs;
    2477         9140 :             goto do_exp1;
    2478              :         }
    2479              :         else
    2480              :         {
    2481        29255 :             goto finish_int;
    2482              :         }
    2483              :     }
    2484              : 
    2485              :     //----------------------------------
    2486              :     //
    2487              :     // DIGIT
    2488              :     // first significant digit
    2489              :     // to the right of decimal
    2490              :     //
    2491      2016835 : do_num7:
    2492              :     {
    2493      2016835 :         if(BOOST_JSON_UNLIKELY(! cs))
    2494              :         {
    2495          691 :             if(BOOST_JSON_UNLIKELY(more_))
    2496              :             {
    2497          687 :                 if(BOOST_JSON_UNLIKELY(
    2498              :                     ! h_.on_number_part(
    2499              :                         {begin, cs.used(begin)}, ec_)))
    2500           35 :                     return fail(cs.begin());
    2501              : 
    2502              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2503           96 :                     num_buf_.append( begin, cs.used(begin) );
    2504          617 :                 return suspend(cs.begin(), state::num7, num);
    2505              :             }
    2506              :             // digit required
    2507              :             BOOST_STATIC_CONSTEXPR source_location loc
    2508              :                 = BOOST_CURRENT_LOCATION;
    2509            4 :             return fail(cs.begin(), error::syntax, &loc);
    2510              :         }
    2511      2016144 :         char const c = *cs;
    2512      2016144 :         if(BOOST_JSON_UNLIKELY(
    2513              :             c < '0' || c > '9'))
    2514              :         {
    2515              :             // digit required
    2516              :             BOOST_STATIC_CONSTEXPR source_location loc
    2517              :                 = BOOST_CURRENT_LOCATION;
    2518          169 :             return fail(cs.begin(), error::syntax, &loc);
    2519              :         }
    2520              :     }
    2521              : 
    2522              :     //----------------------------------
    2523              :     //
    2524              :     // 1*DIGIT
    2525              :     // significant digits
    2526              :     // to the right of decimal
    2527              :     //
    2528      2034436 : do_num8:
    2529      3277926 :     for(;;)
    2530              :     {
    2531      5314862 :         if(BOOST_JSON_UNLIKELY(! cs))
    2532              :         {
    2533        12816 :             if(BOOST_JSON_UNLIKELY(more_))
    2534              :             {
    2535        11080 :                 if(BOOST_JSON_UNLIKELY(
    2536              :                     ! h_.on_number_part(
    2537              :                         {begin, cs.used(begin)}, ec_)))
    2538           67 :                     return fail(cs.begin());
    2539              : 
    2540              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2541         3442 :                     num_buf_.append( begin, cs.used(begin) );
    2542        10945 :                 return suspend(cs.begin(), state::num8, num);
    2543              :             }
    2544         1736 :             goto finish_dub;
    2545              :         }
    2546      5302046 :         char const c = *cs;
    2547      5302046 :         if(BOOST_JSON_LIKELY(
    2548              :             c >= '0' && c <= '9'))
    2549              :         {
    2550      5284910 :             ++cs;
    2551      5279817 :             if(!no_parsing && BOOST_JSON_LIKELY(
    2552              :                 num.mant <= 9007199254740991)) // 2^53-1
    2553              :             {
    2554      3277926 :                 if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
    2555              :                 {
    2556              :                     BOOST_STATIC_CONSTEXPR source_location loc
    2557              :                         = BOOST_CURRENT_LOCATION;
    2558            0 :                     return fail(cs.begin(), error::exponent_overflow, &loc);
    2559              :                 }
    2560      3277926 :                 --num.bias;
    2561      3277926 :                 num.mant = 10 * num.mant + ( c - '0' );
    2562              :             }
    2563              :             else
    2564              :             {
    2565      2006984 :                 goto do_num5;
    2566              :             }
    2567              :         }
    2568        17136 :         else if((c | 32) == 'e')
    2569              :         {
    2570        11133 :             ++cs;
    2571        11133 :             goto do_exp1;
    2572              :         }
    2573              :         else
    2574              :         {
    2575         6003 :             goto finish_dub;
    2576              :         }
    2577              :     }
    2578              : 
    2579              :     //----------------------------------
    2580              :     //
    2581              :     // *[+-]
    2582              :     //
    2583      2031210 : do_exp1:
    2584      2031210 :     if(BOOST_JSON_UNLIKELY(! cs))
    2585              :     {
    2586          565 :         if(BOOST_JSON_UNLIKELY(
    2587              :             ! h_.on_number_part(
    2588              :                 {begin, cs.used(begin)}, ec_)))
    2589           48 :             return fail(cs.begin());
    2590              : 
    2591              :         BOOST_IF_CONSTEXPR( precise_parsing )
    2592           46 :             num_buf_.append( begin, cs.used(begin) );
    2593          469 :         return maybe_suspend(
    2594          469 :             cs.begin(), state::exp1, num);
    2595              :     }
    2596      2030645 :     if(*cs == '+')
    2597              :     {
    2598         1931 :         ++cs;
    2599              :     }
    2600      2028714 :     else if(*cs == '-')
    2601              :     {
    2602      1001935 :         ++cs;
    2603      1001935 :         num.frac = true;
    2604              :     }
    2605              : 
    2606              :     //----------------------------------
    2607              :     //
    2608              :     // DIGIT
    2609              :     // first digit of the exponent
    2610              :     //
    2611      1026779 : do_exp2:
    2612              :     {
    2613      2030770 :         if(BOOST_JSON_UNLIKELY(! cs))
    2614              :         {
    2615          172 :             if(BOOST_JSON_UNLIKELY(more_))
    2616              :             {
    2617          163 :                 if(BOOST_JSON_UNLIKELY(
    2618              :                     ! h_.on_number_part(
    2619              :                         {begin, cs.used(begin)}, ec_)))
    2620           19 :                     return fail(cs.begin());
    2621              : 
    2622              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2623            4 :                     num_buf_.append( begin, cs.used(begin) );
    2624          125 :                 return suspend(cs.begin(), state::exp2, num);
    2625              :             }
    2626              :             // digit required
    2627              :             BOOST_STATIC_CONSTEXPR source_location loc
    2628              :                 = BOOST_CURRENT_LOCATION;
    2629            9 :             return fail(cs.begin(), error::syntax, &loc);
    2630              :         }
    2631      2030598 :         char const c = *cs;
    2632      2030598 :         if(BOOST_JSON_UNLIKELY(
    2633              :             c < '0' || c > '9'))
    2634              :         {
    2635              :             // digit required
    2636              :             BOOST_STATIC_CONSTEXPR source_location loc
    2637              :                 = BOOST_CURRENT_LOCATION;
    2638          508 :             return fail(cs.begin(), error::syntax, &loc);
    2639              :         }
    2640      2030090 :         ++cs;
    2641      2030090 :         num.exp = c - '0';
    2642              :     }
    2643              : 
    2644              :     //----------------------------------
    2645              :     //
    2646              :     // 1*DIGIT
    2647              :     // subsequent digits in the exponent
    2648              :     //
    2649      2042113 : do_exp3:
    2650      5466102 :     for(;;)
    2651              :     {
    2652      7508215 :         if(BOOST_JSON_UNLIKELY(! cs))
    2653              :         {
    2654      2020530 :             if(BOOST_JSON_UNLIKELY(more_))
    2655              :             {
    2656        12177 :                 if(BOOST_JSON_UNLIKELY(
    2657              :                     ! h_.on_number_part(
    2658              :                         {begin, cs.used(begin)}, ec_)))
    2659           77 :                     return fail(cs.begin());
    2660              : 
    2661              :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2662         2873 :                     num_buf_.append( begin, cs.used(begin) );
    2663        12023 :                 return suspend(cs.begin(), state::exp3, num);
    2664              :             }
    2665              :         }
    2666              :         else
    2667              :         {
    2668      5487685 :             char const c = *cs;
    2669      5487685 :             if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
    2670              :             {
    2671      5466102 :                 if(BOOST_JSON_UNLIKELY(
    2672              :                 //              2147483647 INT_MAX
    2673              :                     num.exp  >  214748364 ||
    2674              :                     (num.exp == 214748364 && c > '7')
    2675              :                 ))
    2676         3855 :                     num.exp = INT_MAX;
    2677              :                 else BOOST_IF_CONSTEXPR( !no_parsing )
    2678      4921395 :                     num.exp = 10 * num.exp + ( c - '0' );
    2679              : 
    2680      5466102 :                 ++cs;
    2681      5466102 :                 continue;
    2682              :             }
    2683              :         }
    2684      2029936 :         BOOST_ASSERT(num.exp >= 0);
    2685      2029936 :         if ( num.frac )
    2686              :         {
    2687      1001799 :             if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
    2688              :             {
    2689              :                 // if exponent overflowed, bias is a very large negative
    2690              :                 // number, and mantissa isn't zero, then we cannot parse the
    2691              :                 // number correctly
    2692           91 :                 if(BOOST_JSON_UNLIKELY(
    2693              :                     (num.exp == INT_MAX) &&
    2694              :                     (num.bias < 0) &&
    2695              :                     (num.exp + num.bias < 308) &&
    2696              :                     num.mant ))
    2697              :                 {
    2698              :                     BOOST_STATIC_CONSTEXPR source_location loc
    2699              :                         = BOOST_CURRENT_LOCATION;
    2700            0 :                     return fail(cs.begin(), error::exponent_overflow, &loc);
    2701              :                 }
    2702              : 
    2703           91 :                 num.bias = 0;
    2704           91 :                 num.exp = INT_MAX;
    2705              :             }
    2706              :         }
    2707      1028137 :         else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
    2708              :         {
    2709              :             // if exponent overflowed, bias is a very large positive number,
    2710              :             // and mantissa isn't zero, then we cannot parse the
    2711              :             // number correctly
    2712            0 :             if(BOOST_JSON_UNLIKELY(
    2713              :                 (num.exp == INT_MAX) &&
    2714              :                 (num.bias > 0) &&
    2715              :                 (num.exp - num.bias < 308) &&
    2716              :                 num.mant ))
    2717              :             {
    2718              :                 BOOST_STATIC_CONSTEXPR source_location loc
    2719              :                     = BOOST_CURRENT_LOCATION;
    2720            0 :                 return fail(cs.begin(), error::exponent_overflow, &loc);
    2721              :             }
    2722              : 
    2723            0 :             num.bias = 0;
    2724            0 :             num.exp = INT_MAX;
    2725              :         }
    2726      2029936 :         goto finish_dub;
    2727              :     }
    2728              : 
    2729        30361 : finish_int:
    2730        28432 :     if(negative || (!stack_empty && num.neg))
    2731              :     {
    2732         2531 :         if(BOOST_JSON_UNLIKELY(
    2733              :             ! h_.on_int64(static_cast<
    2734              :                 int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
    2735          309 :             return fail(cs.begin());
    2736         1914 :         return cs.begin();
    2737              :     }
    2738        27830 :     if(num.mant <= INT64_MAX)
    2739              :     {
    2740        27530 : finish_signed:
    2741        30805 :         if(BOOST_JSON_UNLIKELY(
    2742              :             ! h_.on_int64(static_cast<
    2743              :                 int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
    2744         2260 :             return fail(cs.begin());
    2745        26285 :         return cs.begin();
    2746              :     }
    2747          319 :     if(BOOST_JSON_UNLIKELY(
    2748              :         ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
    2749           33 :         return fail(cs.begin());
    2750          254 :     return cs.begin();
    2751      2052261 : finish_dub:
    2752              :     double d;
    2753      2052261 :     std::size_t const size = cs.used(begin);
    2754      2052261 :     BOOST_ASSERT( !num_buf_.size() || precise_parsing );
    2755              :     BOOST_IF_CONSTEXPR( precise_parsing )
    2756              :     {
    2757      1009310 :         char const* data = begin;
    2758      1009310 :         std::size_t full_size = size;
    2759              :          // if we previously suspended or if the current input ends with the
    2760              :          // number, we need to copy the current part of the number to the
    2761              :          // temporary buffer
    2762      1009310 :         if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
    2763              :         {
    2764         4771 :             data = num_buf_.append( begin, size );
    2765         4771 :             full_size = num_buf_.size();
    2766              :         }
    2767      1009310 :         auto const err = detail::charconv::from_chars(
    2768              :             data, data + full_size, d );
    2769      1009310 :         BOOST_ASSERT( err.ec != std::errc::invalid_argument );
    2770      1009310 :         BOOST_ASSERT( err.ptr == data + full_size );
    2771              :         (void)err;
    2772              :     }
    2773              :     else BOOST_IF_CONSTEXPR( no_parsing )
    2774         9258 :         d = 0;
    2775              :     else
    2776      1033693 :         d = detail::dec_to_float(
    2777              :             num.mant,
    2778       531741 :             num.bias + (num.frac ?
    2779       501952 :                 -num.exp : num.exp),
    2780      1033693 :             num.neg);
    2781      2052261 :     if(BOOST_JSON_UNLIKELY(
    2782              :         ! h_.on_double(d, {begin, size}, ec_)))
    2783         1903 :         return fail(cs.begin());
    2784      2048455 :     return cs.begin();
    2785              : }
    2786              : 
    2787              : //----------------------------------------------------------
    2788              : 
    2789              : template<class Handler>
    2790              : template<class... Args>
    2791      2164579 : basic_parser<Handler>::
    2792              : basic_parser(
    2793              :     parse_options const& opt,
    2794              :     Args&&... args)
    2795      2164571 :     : h_(std::forward<Args>(args)...)
    2796      2164579 :     , opt_(opt)
    2797              : {
    2798      2164579 : }
    2799              : 
    2800              : //----------------------------------------------------------
    2801              : 
    2802              : template<class Handler>
    2803              : void
    2804      4153127 : basic_parser<Handler>::
    2805              : reset() noexcept
    2806              : {
    2807      4153127 :     ec_ = {};
    2808      4153127 :     st_.clear();
    2809      4153127 :     more_ = true;
    2810      4153127 :     done_ = false;
    2811      4153127 :     clean_ = true;
    2812      4153127 :     num_buf_.clear();
    2813      4153127 : }
    2814              : 
    2815              : template<class Handler>
    2816              : void
    2817           16 : basic_parser<Handler>::
    2818              : fail(system::error_code ec) noexcept
    2819              : {
    2820           16 :     if(! ec)
    2821              :     {
    2822              :         // assign an arbitrary
    2823              :         // error code to prevent UB
    2824            0 :         BOOST_JSON_FAIL(ec_, error::incomplete);
    2825              :     }
    2826              :     else
    2827              :     {
    2828           16 :         ec_ = ec;
    2829              :     }
    2830           16 :     done_ = false;
    2831           16 : }
    2832              : 
    2833              : //----------------------------------------------------------
    2834              : 
    2835              : template<class Handler>
    2836              : std::size_t
    2837      2334148 : basic_parser<Handler>::
    2838              : write_some(
    2839              :     bool more,
    2840              :     char const* data,
    2841              :     std::size_t size,
    2842              :     system::error_code& ec)
    2843              : {
    2844              :     // see if we exited via exception
    2845              :     // on the last call to write_some
    2846      2334148 :     if(! clean_)
    2847              :     {
    2848              :         // prevent UB
    2849            1 :         if(! ec_)
    2850              :         {
    2851            1 :             BOOST_JSON_FAIL(ec_, error::exception);
    2852              :         }
    2853              :     }
    2854      2334148 :     if(ec_)
    2855              :     {
    2856              :         // error is sticky
    2857            5 :         ec = ec_;
    2858            5 :         return 0;
    2859              :     }
    2860      2334143 :     clean_ = false;
    2861      2334143 :     more_ = more;
    2862      2334143 :     end_ = data + size;
    2863              :     const char* p;
    2864      2334143 :     if(BOOST_JSON_LIKELY(st_.empty()))
    2865              :     {
    2866              :         // first time
    2867      2164565 :         depth_ = opt_.max_depth;
    2868      2164565 :         if(BOOST_JSON_UNLIKELY(
    2869              :             ! h_.on_document_begin(ec_)))
    2870              :         {
    2871         7889 :             ec = ec_;
    2872         7889 :             return 0;
    2873              :         }
    2874      2148786 :         p = parse_document(data, std::true_type());
    2875              :     }
    2876              :     else
    2877              :     {
    2878       169578 :         p = parse_document(data, std::false_type());
    2879              :     }
    2880              : 
    2881      2299265 :     if(BOOST_JSON_LIKELY(p != sentinel()))
    2882              :     {
    2883      2099051 :         BOOST_ASSERT(! ec_);
    2884      2099051 :         if(! done_)
    2885              :         {
    2886      2031637 :             done_ = true;
    2887      2031637 :             h_.on_document_end(ec_);
    2888              :         }
    2889              :     }
    2890              :     else
    2891              :     {
    2892       200214 :         if(! ec_)
    2893              :         {
    2894       173462 :             if(! more_)
    2895              :             {
    2896          572 :                 BOOST_JSON_FAIL(ec_, error::incomplete);
    2897              :             }
    2898       172890 :             else if(! st_.empty())
    2899              :             {
    2900              :                 // consume as much trailing whitespace in
    2901              :                 // the JSON document as possible, but still
    2902              :                 // consider the parse complete
    2903              :                 state st;
    2904       172890 :                 st_.peek(st);
    2905       172890 :                 if( st == state::doc3 &&
    2906        88550 :                     ! done_)
    2907              :                 {
    2908        70723 :                     done_ = true;
    2909        70723 :                     h_.on_document_end(ec_);
    2910              :                 }
    2911              :             }
    2912              :         }
    2913       198570 :         p = end_;
    2914              :     }
    2915      2293661 :     ec = ec_;
    2916      2293661 :     clean_ = true;
    2917      2293661 :     return p - data;
    2918              : }
    2919              : 
    2920              : template<class Handler>
    2921              : std::size_t
    2922            1 : basic_parser<Handler>::
    2923              : write_some(
    2924              :     bool more,
    2925              :     char const* data,
    2926              :     std::size_t size,
    2927              :     std::error_code& ec)
    2928              : {
    2929            1 :     system::error_code jec;
    2930            1 :     std::size_t const result = write_some(more, data, size, jec);
    2931            1 :     ec = jec;
    2932            1 :     return result;
    2933              : }
    2934              : 
    2935              : #endif
    2936              : 
    2937              : } // namespace json
    2938              : } // namespace boost
    2939              : 
    2940              : #ifdef _MSC_VER
    2941              : #pragma warning(pop)
    2942              : #endif
    2943              : 
    2944              : #endif
        

Generated by: LCOV version 2.1