LCOV - code coverage report
Current view: top level - json - basic_parser_impl.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 99.2 % 1278 1268 10
Test Date: 2026-09-30 17:59:05 Functions: 35.7 % 4091 1462 2629

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
       4                 : //
       5                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7                 : //
       8                 : // Official repository: https://github.com/boostorg/json
       9                 : //
      10                 : 
      11                 : #ifndef BOOST_JSON_BASIC_PARSER_IMPL_HPP
      12                 : #define BOOST_JSON_BASIC_PARSER_IMPL_HPP
      13                 : 
      14                 : #include <boost/json/detail/config.hpp>
      15                 : #include <boost/json/detail/literals.hpp>
      16                 : #include <boost/json/basic_parser.hpp>
      17                 : #include <boost/json/error.hpp>
      18                 : #include <boost/json/detail/buffer.hpp>
      19                 : #include <boost/json/detail/charconv/from_chars.hpp>
      20                 : #include <boost/json/detail/sse2.hpp>
      21                 : #include <boost/mp11/algorithm.hpp>
      22                 : #include <boost/mp11/integral.hpp>
      23                 : #include <cmath>
      24                 : #include <limits>
      25                 : #include <cstring>
      26                 : 
      27                 : #ifdef _MSC_VER
      28                 : #pragma warning(push)
      29                 : #pragma warning(disable: 4702) // unreachable code
      30                 : #pragma warning(disable: 4127) // conditional expression is constant
      31                 : #endif
      32                 : 
      33                 : /*  This file must be manually included to get the
      34                 :     function template definitions for basic_parser.
      35                 : */
      36                 : 
      37                 : /*  Reference:
      38                 : 
      39                 :     https://www.json.org/
      40                 : 
      41                 :     RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
      42                 :     https://tools.ietf.org/html/rfc7159
      43                 : 
      44                 :     https://ampl.com/netlib/fp/dtoa.c
      45                 : */
      46                 : 
      47                 : #ifndef BOOST_JSON_DOCS
      48                 : 
      49                 : namespace boost {
      50                 : namespace json {
      51                 : namespace detail {
      52                 : 
      53                 : inline
      54                 : double
      55 HIT     1035607 : pow10(int exp) noexcept
      56                 : {
      57                 :     static double const tab[618] = {
      58                 :                         1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301,
      59                 : 
      60                 :         1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291,
      61                 :         1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
      62                 :         1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
      63                 :         1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261,
      64                 :         1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251,
      65                 :         1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241,
      66                 :         1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231,
      67                 :         1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221,
      68                 :         1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211,
      69                 :         1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201,
      70                 : 
      71                 :         1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
      72                 :         1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
      73                 :         1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171,
      74                 :         1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161,
      75                 :         1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151,
      76                 :         1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141,
      77                 :         1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131,
      78                 :         1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121,
      79                 :         1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111,
      80                 :         1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
      81                 : 
      82                 :         1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091,
      83                 :         1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081,
      84                 :         1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071,
      85                 :         1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061,
      86                 :         1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051,
      87                 :         1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041,
      88                 :         1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031,
      89                 :         1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021,
      90                 :         1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011,
      91                 :         1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001,
      92                 : 
      93                 :         1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009,
      94                 :         1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019,
      95                 :         1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029,
      96                 :         1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039,
      97                 :         1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049,
      98                 :         1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059,
      99                 :         1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069,
     100                 :         1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079,
     101                 :         1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089,
     102                 :         1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099,
     103                 : 
     104                 :         1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109,
     105                 :         1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119,
     106                 :         1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129,
     107                 :         1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139,
     108                 :         1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149,
     109                 :         1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159,
     110                 :         1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169,
     111                 :         1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
     112                 :         1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189,
     113                 :         1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199,
     114                 : 
     115                 :         1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209,
     116                 :         1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219,
     117                 :         1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229,
     118                 :         1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239,
     119                 :         1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249,
     120                 :         1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259,
     121                 :         1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
     122                 :         1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279,
     123                 :         1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289,
     124                 :         1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299,
     125                 : 
     126                 :         1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 };
     127                 : 
     128         1035607 :     if( exp > 308 )
     129                 :     {
     130             455 :         return std::numeric_limits<double>::infinity();
     131                 :     }
     132         1035152 :     else if( exp < -308 )
     133                 :     {
     134                 :         // due to the way pow10 is used by dec_to_float,
     135                 :         // we can afford to return 0.0 here
     136             151 :         return 0.0;
     137                 :     }
     138                 :     else
     139                 :     {
     140         1035001 :         exp += 308;
     141         1035001 :         BOOST_ASSERT(exp >= 0 && exp < 618);
     142         1035001 :         return tab[exp];
     143                 :     }
     144                 : }
     145                 : 
     146                 : inline
     147                 : double
     148         1043157 : dec_to_float(
     149                 :     std::uint64_t m,
     150                 :     std::int32_t e,
     151                 :     bool neg) noexcept
     152                 : {
     153                 :     // convert to double explicitly to silence warnings
     154         1043157 :     double x = static_cast<double>(m);
     155         1043157 :     if(neg)
     156           17069 :         x = -x;
     157                 : 
     158                 :     // pow10 returns infinity for large exponents,
     159                 :     // and zero times infinity is NaN
     160         1043157 :     if(m == 0)
     161            7550 :         return x;
     162                 : 
     163         1035607 :     if(e < -305)
     164                 :     {
     165            5269 :         x *= 1e-305 ;
     166            5269 :         e += 305;
     167                 :     }
     168                 : 
     169         1035607 :     if(e >= -22 && e < 0)
     170           57637 :         return x / pow10(-e);
     171                 : 
     172          977970 :     return x * pow10(e);
     173                 : }
     174                 : 
     175                 : inline
     176                 : bool
     177                 : is_control(char c) noexcept
     178                 : {
     179                 :     return static_cast<unsigned char>(c) < 32;
     180                 : }
     181                 : 
     182                 : inline
     183                 : int
     184           66931 : hex_digit(unsigned char c) noexcept
     185                 : {
     186                 :     // by Peter Dimov
     187           66931 :     if( c >= '0' && c <= '9' )
     188           35759 :         return c - '0';
     189           31172 :     c &= ~0x20;
     190           31172 :     if( c >= 'A' && c <= 'F' )
     191           30562 :         return 10 + c - 'A';
     192             610 :     return -1;
     193                 : }
     194                 : 
     195                 : } // detail
     196                 : 
     197                 : //----------------------------------------------------------
     198                 : 
     199                 : template< class Handler >
     200                 : template< bool StackEmpty_, char First_ >
     201                 : struct basic_parser<Handler>::
     202                 : parse_number_helper
     203                 : {
     204                 :     basic_parser* parser;
     205                 :     char const* p;
     206                 : 
     207                 :     template< std::size_t N >
     208                 :     char const*
     209        10515990 :     operator()( mp11::mp_size_t<N> ) const
     210                 :     {
     211        21026475 :         return parser->parse_number(
     212        10515990 :             p,
     213                 :             std::integral_constant<bool, StackEmpty_>(),
     214                 :             std::integral_constant<char, First_>(),
     215                 :             std::integral_constant<
     216        10510486 :                 number_precision, static_cast<number_precision>(N)>() );
     217                 :     }
     218                 : };
     219                 : 
     220                 : //----------------------------------------------------------
     221                 : 
     222                 : template<class Handler>
     223                 : void
     224         8602432 : basic_parser<Handler>::
     225                 : reserve()
     226                 : {
     227         8602432 :     if(BOOST_JSON_LIKELY(
     228                 :         ! st_.empty()))
     229           37477 :         return;
     230                 :     // Reserve the largest stack we need,
     231                 :     // to avoid reallocation during suspend.
     232        17129910 :     st_.reserve(
     233                 :         sizeof(state) + // document parsing state
     234                 :         (sizeof(state) +
     235         8564955 :             sizeof(std::size_t)) * depth() + // array and object state + size
     236                 :         sizeof(state) + // value parsing state
     237                 :         sizeof(std::size_t) + // string size
     238                 :         sizeof(state)); // comment state
     239                 : }
     240                 : 
     241                 : //----------------------------------------------------------
     242                 : //
     243                 : // The sentinel value is returned by parse functions
     244                 : // to indicate that the parser failed, or suspended.
     245                 : // this is used as it is distinct from all valid values
     246                 : // for data in write
     247                 : 
     248                 : template<class Handler>
     249                 : const char*
     250        47301147 : basic_parser<Handler>::
     251                 : sentinel()
     252                 : {
     253                 :     // the "+1" ensures that the returned pointer is unique even if
     254                 :     // the given input buffer borders on this object
     255                 :     return reinterpret_cast<
     256        47301147 :         const char*>(this) + 1;
     257                 : }
     258                 : 
     259                 : template<class Handler>
     260                 : bool
     261        10851991 : basic_parser<Handler>::
     262                 : incomplete(
     263                 :     const detail::const_stream_wrapper& cs)
     264                 : {
     265        10851991 :     return cs.begin() == sentinel();
     266                 : }
     267                 : 
     268                 : //----------------------------------------------------------
     269                 : //
     270                 : // These functions are declared with the BOOST_NOINLINE
     271                 : // attribute to avoid polluting the parsers hot-path.
     272                 : // They return the canary value to indicate suspension
     273                 : // or failure.
     274                 : 
     275                 : template<class Handler>
     276                 : const char*
     277                 : basic_parser<Handler>::
     278                 : suspend_or_fail(state st)
     279                 : {
     280                 :     if(BOOST_JSON_LIKELY(
     281                 :         ! ec_ && more_))
     282                 :     {
     283                 :         // suspend
     284                 :         reserve();
     285                 :         st_.push_unchecked(st);
     286                 :     }
     287                 :     return sentinel();
     288                 : }
     289                 : 
     290                 : template<class Handler>
     291                 : const char*
     292           56179 : basic_parser<Handler>::
     293                 : suspend_or_fail(
     294                 :     state st,
     295                 :     std::size_t n)
     296                 : {
     297           56179 :     if(BOOST_JSON_LIKELY(
     298                 :         ! ec_ && more_))
     299                 :     {
     300                 :         // suspend
     301           35861 :         reserve();
     302           35861 :         st_.push_unchecked(n);
     303           35861 :         st_.push_unchecked(st);
     304                 :     }
     305           56179 :     return sentinel();
     306                 : }
     307                 : 
     308                 : 
     309                 : template<class Handler>
     310                 : const char*
     311           19074 : basic_parser<Handler>::
     312                 : fail(const char* p) noexcept
     313                 : {
     314           19074 :     BOOST_ASSERT( p != sentinel() );
     315           19074 :     end_ = p;
     316           19074 :     return sentinel();
     317                 : }
     318                 : 
     319                 : template<class Handler>
     320                 : const char*
     321            7781 : basic_parser<Handler>::
     322                 : fail(
     323                 :     const char* p,
     324                 :     error ev,
     325                 :     source_location const* loc) noexcept
     326                 : {
     327            7781 :     BOOST_ASSERT( p != sentinel() );
     328            7781 :     end_ = p;
     329            7781 :     ec_.assign(ev, loc);
     330            7781 :     return sentinel();
     331                 : }
     332                 : 
     333                 : template<class Handler>
     334                 : const char*
     335           11323 : basic_parser<Handler>::
     336                 : maybe_suspend(
     337                 :     const char* p,
     338                 :     state st)
     339                 : {
     340           11323 :     if( p != sentinel() )
     341            9445 :         end_ = p;
     342           11323 :     if(BOOST_JSON_LIKELY(more_))
     343                 :     {
     344                 :         // suspend
     345           11050 :         reserve();
     346           11050 :         st_.push_unchecked(st);
     347                 :     }
     348           11323 :     return sentinel();
     349                 : }
     350                 : 
     351                 : template<class Handler>
     352                 : const char*
     353           41250 : basic_parser<Handler>::
     354                 : maybe_suspend(
     355                 :     const char* p,
     356                 :     state st,
     357                 :     std::size_t n)
     358                 : {
     359           41250 :     BOOST_ASSERT( p != sentinel() );
     360           41250 :     end_ = p;
     361           41250 :     if(BOOST_JSON_LIKELY(more_))
     362                 :     {
     363                 :         // suspend
     364           40842 :         reserve();
     365           40842 :         st_.push_unchecked(n);
     366           40842 :         st_.push_unchecked(st);
     367                 :     }
     368           41250 :     return sentinel();
     369                 : }
     370                 : 
     371                 : template<class Handler>
     372                 : const char*
     373            1132 : basic_parser<Handler>::
     374                 : maybe_suspend(
     375                 :     const char* p,
     376                 :     state st,
     377                 :     const number& num)
     378                 : {
     379            1132 :     BOOST_ASSERT( p != sentinel() );
     380            1132 :     end_ = p;
     381            1132 :     if(BOOST_JSON_LIKELY(more_))
     382                 :     {
     383                 :         // suspend
     384            1132 :         num_ = num;
     385            1132 :         reserve();
     386            1132 :         st_.push_unchecked(st);;
     387                 :     }
     388            1132 :     return sentinel();
     389                 : }
     390                 : 
     391                 : template<class Handler>
     392                 : const char*
     393           88657 : basic_parser<Handler>::
     394                 : suspend(
     395                 :     const char* p,
     396                 :     state st)
     397                 : {
     398           88657 :     BOOST_ASSERT( p != sentinel() );
     399           88657 :     end_ = p;
     400                 :     // suspend
     401           88657 :     reserve();
     402           88657 :     st_.push_unchecked(st);
     403           88657 :     return sentinel();
     404                 : }
     405                 : 
     406                 : template<class Handler>
     407                 : const char*
     408         8424890 : basic_parser<Handler>::
     409                 : suspend(
     410                 :     const char* p,
     411                 :     state st,
     412                 :     const number& num)
     413                 : {
     414         8424890 :     BOOST_ASSERT( p != sentinel() );
     415         8424890 :     end_ = p;
     416                 :     // suspend
     417         8424890 :     num_ = num;
     418         8424890 :     reserve();
     419         8424890 :     st_.push_unchecked(st);
     420         8424890 :     return sentinel();
     421                 : }
     422                 : 
     423                 : template<class Handler>
     424                 : template<
     425                 :     bool StackEmpty_/*,
     426                 :     bool Terminal_*/>
     427                 : const char*
     428           21764 : basic_parser<Handler>::
     429                 : parse_comment(const char* p,
     430                 :     std::integral_constant<bool, StackEmpty_> stack_empty,
     431                 :     /*std::integral_constant<bool, Terminal_>*/ bool terminal)
     432                 : {
     433           21764 :     detail::const_stream_wrapper cs(p, end_);
     434           21764 :     const char* start = cs.begin();
     435                 :     std::size_t remain;
     436           21764 :     if(! stack_empty && ! st_.empty())
     437                 :     {
     438                 :         state st;
     439            3515 :         st_.pop(st);
     440            3515 :         switch(st)
     441                 :         {
     442                 :             default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
     443             538 :             case state::com1: goto do_com1;
     444            2323 :             case state::com2: goto do_com2;
     445             438 :             case state::com3: goto do_com3;
     446             216 :             case state::com4: goto do_com4;
     447                 :         }
     448                 :     }
     449           18249 :     BOOST_ASSERT(*cs == '/');
     450           18249 :     ++cs;
     451           18787 : do_com1:
     452           18787 :     if(BOOST_JSON_UNLIKELY(! cs))
     453             555 :         return maybe_suspend(cs.begin(), state::com1);
     454           18232 :     switch(*cs)
     455                 :     {
     456               5 :     default:
     457                 :         {
     458                 :             BOOST_STATIC_CONSTEXPR source_location loc
     459                 :                 = BOOST_CURRENT_LOCATION;
     460               5 :             return fail(cs.begin(), error::syntax, &loc);
     461                 :         }
     462           10543 :     case '/':
     463           10543 :         ++cs;
     464           12866 : do_com2:
     465                 :         // KRYSTIAN TODO: this is a mess, we have to fix this
     466           12866 :         remain = cs.remain();
     467           25732 :         cs = remain ? static_cast<const char*>(
     468           12866 :             std::memchr(cs.begin(), '\n', remain)) : sentinel();
     469           12866 :         if(! cs.begin())
     470            2143 :             cs = sentinel();
     471           12866 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     472                 :         {
     473                 :             // if the doc does not terminate
     474                 :             // with a newline, treat it as the
     475                 :             // end of the comment
     476            2574 :             if(terminal && ! more_)
     477                 :             {
     478              39 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment(
     479                 :                     {start, cs.remain(start)}, ec_)))
     480               2 :                     return fail(cs.end());
     481              35 :                 return cs.end();
     482                 :             }
     483            2535 :             if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     484                 :                 {start, cs.remain(start)}, ec_)))
     485              96 :                 return fail(cs.end());
     486            2343 :             if(terminal)
     487             106 :                 return suspend(cs.end(), state::com2);
     488            2237 :             return maybe_suspend(cs.end(), state::com2);
     489                 :         }
     490           10292 :         break;
     491            1684 :     case '*':
     492                 :         do
     493                 :         {
     494            9368 :             ++cs;
     495            9806 : do_com3:
     496                 :             // KRYSTIAN TODO: this is a mess, we have to fix this
     497            9806 :             remain = cs.remain();
     498           19612 :             cs = remain ? static_cast<const char*>(
     499            9806 :                 std::memchr(cs.begin(), '*', remain)) : sentinel();
     500            9806 :             if(! cs.begin())
     501             242 :                 cs = sentinel();
     502                 :             // stopped inside a c comment
     503            9806 :             if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     504                 :             {
     505             503 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     506                 :                     {start, cs.remain(start)}, ec_)))
     507              30 :                     return fail(cs.end());
     508             443 :                 return maybe_suspend(cs.end(), state::com3);
     509                 :             }
     510                 :             // found a asterisk, check if the next char is a slash
     511            9303 :             ++cs;
     512            9519 : do_com4:
     513            9519 :             if(BOOST_JSON_UNLIKELY(! cs))
     514                 :             {
     515             259 :                 if(BOOST_JSON_UNLIKELY(! h_.on_comment_part(
     516                 :                     {start, cs.used(start)}, ec_)))
     517              18 :                     return fail(cs.begin());
     518             223 :                 return maybe_suspend(cs.begin(), state::com4);
     519                 :             }
     520                 :         }
     521            9260 :         while(*cs != '/');
     522                 :     }
     523           17868 :     ++cs;
     524           17868 :     if(BOOST_JSON_UNLIKELY(! h_.on_comment(
     525                 :         {start, cs.used(start)}, ec_)))
     526             968 :         return fail(cs.begin());
     527           15932 :     return cs.begin();
     528                 : }
     529                 : 
     530                 : template<class Handler>
     531                 : template<bool StackEmpty_>
     532                 : const char*
     533        10710592 : basic_parser<Handler>::
     534                 : parse_document(const char* p,
     535                 :     std::integral_constant<bool, StackEmpty_> stack_empty)
     536                 : {
     537        10710592 :     detail::const_stream_wrapper cs(p, end_);
     538        10710592 :     if(! stack_empty && ! st_.empty())
     539                 :     {
     540                 :         state st;
     541         8561473 :         st_.peek(st);
     542         8561473 :         switch(st)
     543                 :         {
     544         8475408 :         default: goto do_doc2;
     545             601 :         case state::doc1:
     546             601 :                  st_.pop(st);
     547             601 :                  goto do_doc1;
     548           85244 :         case state::doc3:
     549           85244 :                  st_.pop(st);
     550           85244 :                  goto do_doc3;
     551             220 :         case state::com1: case state::com2:
     552                 :         case state::com3: case state::com4:
     553             220 :                  goto do_doc4;
     554                 :         }
     555                 :     }
     556         2149119 : do_doc1:
     557         2149720 :     cs = detail::count_whitespace(cs.begin(), cs.end());
     558         2149720 :     if(BOOST_JSON_UNLIKELY(! cs))
     559             633 :         return maybe_suspend(cs.begin(), state::doc1);
     560         2149087 : do_doc2:
     561        10624495 :     switch(+opt_.allow_comments |
     562        10624495 :         (opt_.allow_trailing_commas << 1) |
     563        10624495 :         (opt_.allow_invalid_utf8 << 2))
     564                 :     {
     565                 :     // no extensions
     566        10600782 :     default:
     567        10600782 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
     568        10585560 :         break;
     569                 :     // comments
     570           13582 :     case 1:
     571           13582 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::false_type(), opt_.allow_invalid_utf16);
     572           11314 :         break;
     573                 :     // trailing
     574            6710 :     case 2:
     575            6710 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
     576            5117 :         break;
     577                 :     // comments & trailing
     578             761 :     case 3:
     579             761 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::false_type(), opt_.allow_invalid_utf16);
     580             761 :         break;
     581                 :     // skip validation
     582             760 :     case 4:
     583             760 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
     584             760 :         break;
     585                 :     // comments & skip validation
     586             760 :     case 5:
     587             760 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::false_type(), std::true_type(), opt_.allow_invalid_utf16);
     588             760 :         break;
     589                 :     // trailing & skip validation
     590             760 :     case 6:
     591             760 :         cs = parse_value(cs.begin(), stack_empty, std::false_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
     592             760 :         break;
     593                 :     // comments & trailing & skip validation
     594             380 :     case 7:
     595             380 :         cs = parse_value(cs.begin(), stack_empty, std::true_type(), std::true_type(), std::true_type(), opt_.allow_invalid_utf16);
     596             380 :         break;
     597                 :     }
     598        10605412 :     if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     599                 :         // the appropriate state has already been pushed into stack
     600         8502706 :         return sentinel();
     601         2102706 : do_doc3:
     602         2188282 :     cs = detail::count_whitespace(cs.begin(), cs.end());
     603         2188282 :     if(BOOST_JSON_UNLIKELY(! cs))
     604                 :     {
     605         2185684 :         if(more_)
     606           88551 :             return suspend(cs.begin(), state::doc3);
     607                 :     }
     608            2598 :     else if(opt_.allow_comments && *cs == '/')
     609                 :     {
     610             536 : do_doc4:
     611             756 :         cs = parse_comment(cs.begin(), stack_empty, std::true_type());
     612             671 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
     613             339 :             return sentinel();
     614             332 :         goto do_doc3;
     615                 :     }
     616         2099195 :     return cs.begin();
     617                 : }
     618                 : 
     619                 : template<class Handler>
     620                 : template<
     621                 :     bool StackEmpty_,
     622                 :     bool AllowComments_/*,
     623                 :     bool AllowTrailing_,
     624                 :     bool AllowBadUTF8_*/>
     625                 : const char*
     626        10742129 : basic_parser<Handler>::
     627                 : parse_value(const char* p,
     628                 :     std::integral_constant<bool, StackEmpty_> stack_empty,
     629                 :     std::integral_constant<bool, AllowComments_> allow_comments,
     630                 :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
     631                 :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
     632                 :     bool allow_bad_utf16)
     633                 : {
     634        10742129 :     if(stack_empty || st_.empty())
     635                 :     {
     636         2248335 : loop:
     637         2253251 :         switch(*p)
     638                 :         {
     639           22761 :         case '0':
     640           22761 :             return mp11::mp_with_index<3>(
     641           22761 :                 static_cast<unsigned char>(opt_.numbers),
     642           22100 :                 parse_number_helper<true, '0'>{ this, p });
     643           25185 :         case '-':
     644           25185 :             return mp11::mp_with_index<3>(
     645           25185 :                 static_cast<unsigned char>(opt_.numbers),
     646           24073 :                 parse_number_helper<true, '-'>{ this, p });
     647         2042025 :         case '1': case '2': case '3':
     648                 :         case '4': case '5': case '6':
     649                 :         case '7': case '8': case '9':
     650         2042025 :             return mp11::mp_with_index<3>(
     651         2042025 :                 static_cast<unsigned char>(opt_.numbers),
     652         2039149 :                 parse_number_helper<true, '+'>{ this, p });
     653           11381 :         case 'n':
     654           11381 :             return parse_literal( p, detail::literals_c<detail::literals::null>() );
     655             664 :         case 't':
     656             664 :             return parse_literal( p, detail::literals_c<detail::literals::true_>() );
     657             722 :         case 'f':
     658             722 :             return parse_literal( p, detail::literals_c<detail::literals::false_>() );
     659             681 :         case 'I':
     660             681 :             if( !opt_.allow_infinity_and_nan )
     661                 :             {
     662                 :                 BOOST_STATIC_CONSTEXPR source_location loc
     663                 :                     = BOOST_CURRENT_LOCATION;
     664              24 :                 return fail(p, error::syntax, &loc);
     665                 :             }
     666             657 :             return parse_literal( p, detail::literals_c<detail::literals::infinity>() );
     667             231 :         case 'N':
     668             231 :             if( !opt_.allow_infinity_and_nan )
     669                 :             {
     670                 :                 BOOST_STATIC_CONSTEXPR source_location loc
     671                 :                     = BOOST_CURRENT_LOCATION;
     672              30 :                 return fail(p, error::syntax, &loc);
     673                 :             }
     674             201 :             return parse_literal(p, detail::literals_c<detail::literals::nan>() );
     675           47587 :         case '"':
     676           47587 :             return parse_string(p, std::true_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
     677           20618 :         case '[':
     678           20618 :             return parse_array(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     679           74131 :         case '{':
     680           74131 :             return parse_object(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     681            6144 :         case '/':
     682            6144 :             if(! allow_comments)
     683                 :             {
     684                 :                 BOOST_STATIC_CONSTEXPR source_location loc
     685                 :                     = BOOST_CURRENT_LOCATION;
     686             284 :                 return fail(p, error::syntax, &loc);
     687                 :             }
     688            5860 :             p = parse_comment(p, stack_empty, std::false_type());
     689                 :             // KRYSTIAN NOTE: incomplete takes const_stream, we either
     690                 :             // can add an overload, change the existing one to take a pointer,
     691                 :             // or just leave it as is
     692            5621 :             if(BOOST_JSON_UNLIKELY(p == sentinel()))
     693             602 :                 return maybe_suspend(p, state::val2);
     694                 :             BOOST_FALLTHROUGH;
     695                 :         case ' ':
     696                 :         case '\t':
     697                 :         case '\n':
     698                 :         case '\r':
     699            5035 :             p = detail::count_whitespace(p, end_);
     700            5035 :             if(BOOST_JSON_UNLIKELY(p == end_))
     701             119 :                 return maybe_suspend(p, state::val1);
     702            4916 :             goto loop;
     703            1105 :         default:
     704                 :             {
     705                 :                 BOOST_STATIC_CONSTEXPR source_location loc
     706                 :                     = BOOST_CURRENT_LOCATION;
     707            1105 :                 return fail(p, error::syntax, &loc);
     708                 :             }
     709                 :         }
     710                 :     }
     711         8493794 :     return resume_value(p, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     712                 : }
     713                 : 
     714                 : template<class Handler>
     715                 : template<
     716                 :     bool AllowComments_/*,
     717                 :     bool AllowTrailing_,
     718                 :     bool AllowBadUTF8_*/>
     719                 : const char*
     720         8493794 : basic_parser<Handler>::
     721                 : resume_value(const char* p,
     722                 :     std::integral_constant<bool, AllowComments_> allow_comments,
     723                 :     /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
     724                 :     /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
     725                 :     bool allow_bad_utf16)
     726                 : {
     727                 :     state st;
     728         8493794 :     st_.peek(st);
     729         8493794 :     switch(st)
     730                 :     {
     731                 :     default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
     732            1924 :     case state::lit1:
     733            1924 :         return parse_literal(p,  detail::literals_c<detail::literals::resume>() );
     734                 : 
     735           23268 :     case state::str1: case state::str2:
     736                 :     case state::str8:
     737           23268 :         return parse_string(p, std::false_type(), std::false_type(), allow_bad_utf8, allow_bad_utf16);
     738                 : 
     739            5730 :     case state::arr1: case state::arr2:
     740                 :     case state::arr3: case state::arr4:
     741                 :     case state::arr5: case state::arr6:
     742            5730 :         return parse_array(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     743                 : 
     744           35058 :     case state::obj1: case state::obj2:
     745                 :     case state::obj3: case state::obj4:
     746                 :     case state::obj5: case state::obj6:
     747                 :     case state::obj7: case state::obj8:
     748                 :     case state::obj9: case state::obj10:
     749                 :     case state::obj11:
     750           35058 :         return parse_object(p, std::false_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     751                 : 
     752         8426019 :     case state::num1: case state::num2:
     753                 :     case state::num3: case state::num4:
     754                 :     case state::num5: case state::num6:
     755                 :     case state::num7: case state::num8:
     756                 :     case state::exp1: case state::exp2:
     757                 :     case state::exp3:
     758         8426019 :         return mp11::mp_with_index<3>(
     759         8426019 :             static_cast<unsigned char>(opt_.numbers),
     760         8425164 :             parse_number_helper<false, 0>{ this, p });
     761                 : 
     762                 :     // KRYSTIAN NOTE: these are special cases
     763             112 :     case state::val1:
     764                 :     {
     765             112 :         st_.pop(st);
     766             112 :         BOOST_ASSERT(st_.empty());
     767             112 :         p = detail::count_whitespace(p, end_);
     768             112 :         if(BOOST_JSON_UNLIKELY(p == end_))
     769               4 :             return maybe_suspend(p, state::val1);
     770             108 :         return parse_value(p, std::true_type(), allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
     771                 :     }
     772                 : 
     773            1616 :     case state::val2:
     774                 :     {
     775            1616 :         st_.pop(st);
     776            1616 :         p = parse_comment(p, std::false_type(), std::false_type());
     777            1596 :         if(BOOST_JSON_UNLIKELY(p == sentinel()))
     778            1276 :             return maybe_suspend(p, state::val2);
     779             320 :         if(BOOST_JSON_UNLIKELY( p == end_ ))
     780              77 :             return maybe_suspend(p, state::val3);
     781             243 :         BOOST_ASSERT(st_.empty());
     782             243 :         return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
     783                 :     }
     784                 : 
     785              67 :     case state::val3:
     786                 :     {
     787              67 :         st_.pop(st);
     788              67 :         return parse_value(p, std::true_type(), std::true_type(), allow_trailing, allow_bad_utf8, allow_bad_utf16);
     789                 :     }
     790                 :     }
     791                 : }
     792                 : 
     793                 : template<class Handler>
     794                 : template<class Literal>
     795                 : const char*
     796           16565 : basic_parser<Handler>::
     797                 : parse_literal(const char* p, Literal)
     798                 : {
     799                 :     using L = detail::literals;
     800                 : 
     801                 :     std::size_t cur_lit;
     802                 :     std::size_t offset;
     803                 : 
     804           16565 :     detail::const_stream_wrapper cs(p, end_);
     805                 :     BOOST_IF_CONSTEXPR( Literal::value != L::resume )
     806                 :     {
     807           13634 :         constexpr std::size_t index = literal_index(Literal::value);
     808           13634 :         constexpr char const* literal = detail::literal_strings[index];
     809           13634 :         constexpr std::size_t sz = detail::literal_sizes[index];
     810                 : 
     811           13634 :         if(BOOST_JSON_LIKELY( cs.remain() >= sz ))
     812                 :         {
     813           11984 :             int const cmp = std::memcmp(cs.begin(), literal, sz);
     814           11984 :             if( cmp != 0 )
     815                 :             {
     816                 :                 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     817             197 :                 return fail(cs.begin(), error::syntax, &loc);
     818                 :             }
     819                 : 
     820                 :             BOOST_IF_CONSTEXPR( Literal::value == L::null )
     821                 :             {
     822           10789 :                 if(BOOST_JSON_UNLIKELY(
     823                 :                     ! h_.on_null(ec_)))
     824             161 :                     return fail(cs.begin());
     825                 :             }
     826                 :             else BOOST_IF_CONSTEXPR( Literal::value == L::true_ )
     827                 :             {
     828             384 :                 if(BOOST_JSON_UNLIKELY(
     829                 :                     ! h_.on_bool(true, ec_)))
     830              14 :                     return fail(cs.begin());
     831                 :             }
     832                 :             else BOOST_IF_CONSTEXPR( Literal::value == L::false_ )
     833                 :             {
     834             406 :                 if(BOOST_JSON_UNLIKELY(
     835                 :                     ! h_.on_bool(false, ec_)))
     836              13 :                     return fail(cs.begin());
     837                 :             }
     838                 :             else BOOST_IF_CONSTEXPR( Literal::value == L::infinity )
     839                 :             {
     840             103 :                 if(BOOST_JSON_UNLIKELY(
     841                 :                     ! h_.on_double(
     842                 :                         std::numeric_limits<double>::infinity(),
     843                 :                         string_view(literal, sz),
     844                 :                         ec_)))
     845              13 :                     return fail(cs.begin());
     846                 :             }
     847                 :             else BOOST_IF_CONSTEXPR( Literal::value == L::neg_infinity )
     848                 :             {
     849               9 :                 if(BOOST_JSON_UNLIKELY(
     850                 :                     ! h_.on_double(
     851                 :                         -std::numeric_limits<double>::infinity(),
     852                 :                         string_view(literal, sz),
     853                 :                         ec_)))
     854               1 :                     return fail(cs.begin());
     855                 :             }
     856                 :             else BOOST_IF_CONSTEXPR( Literal::value == L::nan )
     857                 :             {
     858              96 :                 if(BOOST_JSON_UNLIKELY(
     859                 :                     ! h_.on_double(
     860                 :                         std::numeric_limits<double>::quiet_NaN(),
     861                 :                         string_view(literal, sz),
     862                 :                         ec_)))
     863              12 :                     return fail(cs.begin());
     864                 :             }
     865                 :             else
     866                 :             {
     867                 :                 BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
     868                 :             }
     869                 : 
     870           11363 :             cs += sz;
     871           11363 :             return cs.begin();
     872                 :         }
     873                 : 
     874            1650 :         offset = 0;
     875            1650 :         cur_lit = index;
     876                 :     }
     877                 :     else
     878                 :     {
     879                 :         state st;
     880            2931 :         st_.pop(st);
     881            2931 :         BOOST_ASSERT( st == state::lit1 );
     882                 : 
     883            2931 :         cur_lit = cur_lit_;
     884            2931 :         offset = lit_offset_;
     885                 :     }
     886                 : 
     887            4581 :     std::size_t const lit_size = detail::literal_sizes[cur_lit];
     888            4581 :     std::size_t const size = (std::min)( lit_size - offset, cs.remain() );
     889            4581 :     int cmp = 0;
     890            4581 :     if(BOOST_JSON_LIKELY( cs.begin() ))
     891            4580 :         cmp = std::memcmp(
     892            4580 :             cs.begin(), detail::literal_strings[cur_lit] + offset, size );
     893            4581 :     if( cmp != 0 )
     894                 :     {
     895                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     896             699 :         return fail(cs.begin(), error::syntax, &loc);
     897                 :     }
     898                 : 
     899            3882 :     if(BOOST_JSON_UNLIKELY( offset + size < lit_size ))
     900                 :     {
     901            1990 :         BOOST_ASSERT( cur_lit < 256 );
     902            1990 :         cur_lit_ = static_cast<unsigned char>( cur_lit );
     903            1990 :         BOOST_ASSERT( offset + size < 256 );
     904            1990 :         lit_offset_ = static_cast<unsigned char>( offset + size );
     905            1990 :         return maybe_suspend(cs.begin() + size, state::lit1);
     906                 :     }
     907                 : 
     908            1892 :     switch( static_cast<L>(cur_lit) )
     909                 :     {
     910             472 :     case L::null:
     911             472 :         if(BOOST_JSON_UNLIKELY(
     912                 :             ! h_.on_null(ec_)))
     913              61 :             return fail(cs.begin());
     914             351 :         break;
     915             152 :     case L::true_:
     916             152 :         if(BOOST_JSON_UNLIKELY(
     917                 :             ! h_.on_bool(true, ec_)))
     918              22 :             return fail(cs.begin());
     919             109 :         break;
     920             198 :     case L::false_:
     921             198 :         if(BOOST_JSON_UNLIKELY(
     922                 :             ! h_.on_bool(false, ec_)))
     923              28 :             return fail(cs.begin());
     924             142 :         break;
     925             308 :     case L::infinity:
     926             308 :         if(BOOST_JSON_UNLIKELY(
     927                 :             ! h_.on_double(
     928                 :                 std::numeric_limits<double>::infinity(),
     929                 :                 string_view(
     930                 :                     detail::literal_strings[ literal_index(L::infinity) ],
     931                 :                     detail::literal_sizes[ literal_index(L::infinity) ]),
     932                 :                 ec_)))
     933              49 :             return fail(cs.begin());
     934             210 :         break;
     935             686 :     case L::neg_infinity:
     936             686 :         if(BOOST_JSON_UNLIKELY(
     937                 :             ! h_.on_double(
     938                 :                 -std::numeric_limits<double>::infinity(),
     939                 :                 string_view(
     940                 :                     detail::literal_strings[ literal_index(L::neg_infinity) ],
     941                 :                     detail::literal_sizes[ literal_index(L::neg_infinity) ]),
     942                 :                 ec_)))
     943             102 :             return fail(cs.begin());
     944             482 :         break;
     945              76 :     case L::nan:
     946              76 :         if(BOOST_JSON_UNLIKELY(
     947                 :             ! h_.on_double(
     948                 :                 std::numeric_limits<double>::quiet_NaN(),
     949                 :                 string_view(
     950                 :                     detail::literal_strings[ literal_index(L::nan) ],
     951                 :                     detail::literal_sizes[ literal_index(L::nan) ]),
     952                 :                 ec_)))
     953              12 :             return fail(cs.begin());
     954              52 :         break;
     955                 :     default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
     956                 :     }
     957                 : 
     958            1346 :     cs += size;
     959            1346 :     return cs.begin();
     960                 : }
     961                 : 
     962                 : //----------------------------------------------------------
     963                 : 
     964                 : template<class Handler>
     965                 : template<bool StackEmpty_, bool IsKey_>
     966                 : const char*
     967          164330 : basic_parser<Handler>::
     968                 : parse_string(const char* p,
     969                 :     std::integral_constant<bool, StackEmpty_> stack_empty,
     970                 :     std::integral_constant<bool, IsKey_> is_key,
     971                 :     bool allow_bad_utf8,
     972                 :     bool allow_bad_utf16)
     973                 : {
     974          164330 :     detail::const_stream_wrapper cs(p, end_);
     975                 :     std::size_t total;
     976                 :     char const* start;
     977                 :     std::size_t size;
     978          164330 :     if(! stack_empty && ! st_.empty())
     979                 :     {
     980                 :         state st;
     981           35915 :         st_.pop(st);
     982           35915 :         st_.pop(total);
     983           35915 :         switch(st)
     984                 :         {
     985                 :         default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
     986            3149 :         case state::str2: goto do_str2;
     987            1868 :         case state::str8: goto do_str8;
     988           30898 :         case state::str1: break;
     989                 :         }
     990                 :     }
     991                 :     else
     992                 :     {
     993          128415 :         BOOST_ASSERT(*cs == '\x22'); // '"'
     994          128415 :         ++cs;
     995          128415 :         total = 0;
     996                 :     }
     997                 : 
     998          167806 : do_str1:
     999          167806 :     start = cs.begin();
    1000          335612 :     cs = allow_bad_utf8?
    1001            2177 :         detail::count_valid<true>(cs.begin(), cs.end()):
    1002          165629 :         detail::count_valid<false>(cs.begin(), cs.end());
    1003          167806 :     size = cs.used(start);
    1004          167806 :     if(is_key)
    1005                 :     {
    1006           46694 :         BOOST_ASSERT(total <= Handler::max_key_size);
    1007           94005 :         if(BOOST_JSON_UNLIKELY(size >
    1008                 :             Handler::max_key_size - total))
    1009                 :         {
    1010                 :             BOOST_STATIC_CONSTEXPR source_location loc
    1011                 :                 = BOOST_CURRENT_LOCATION;
    1012               3 :             return fail(cs.begin(), error::key_too_large, &loc);
    1013                 :         }
    1014                 :     }
    1015                 :     else
    1016                 :     {
    1017           38330 :         BOOST_ASSERT(total <= Handler::max_string_size);
    1018           73801 :         if(BOOST_JSON_UNLIKELY(size >
    1019                 :             Handler::max_string_size - total))
    1020                 :         {
    1021                 :             BOOST_STATIC_CONSTEXPR source_location loc
    1022                 :                 = BOOST_CURRENT_LOCATION;
    1023               3 :             return fail(cs.begin(), error::string_too_large, &loc);
    1024                 :         }
    1025                 :     }
    1026          167800 :     total += size;
    1027          167800 :     if(BOOST_JSON_UNLIKELY(! cs))
    1028                 :     {
    1029                 :         // call handler if the string isn't empty
    1030           33232 :         if(BOOST_JSON_LIKELY(size))
    1031                 :         {
    1032                 :             {
    1033           30066 :                 bool r = is_key?
    1034           12404 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1035           18996 :                     h_.on_string_part( {start, size}, total, ec_ );
    1036                 : 
    1037           28958 :                 if(BOOST_JSON_UNLIKELY(!r))
    1038                 :                 {
    1039            1110 :                     return fail(cs.begin());
    1040                 :                 }
    1041                 :             }
    1042                 :         }
    1043           31014 :         return maybe_suspend(cs.begin(), state::str1, total);
    1044                 :     }
    1045                 :     // at this point all valid characters have been skipped, so any remaining
    1046                 :     // if there are any more characters, they are either escaped, or incomplete
    1047                 :     // utf8, or invalid utf8
    1048          134568 :     if(BOOST_JSON_UNLIKELY(*cs != '\x22')) // '"'
    1049                 :     {
    1050                 :         // sequence is invalid or incomplete
    1051           15081 :         if((*cs & 0x80) && !allow_bad_utf8)
    1052                 :         {
    1053            3472 :             seq_.save(cs.begin(), cs.remain());
    1054            3472 :             if(BOOST_JSON_UNLIKELY(seq_.complete()))
    1055                 :             {
    1056                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    1057                 :                     = BOOST_CURRENT_LOCATION;
    1058            1557 :                 return fail(cs.begin(), error::syntax, &loc);
    1059                 :             }
    1060            1915 :             if(BOOST_JSON_LIKELY(size))
    1061                 :             {
    1062             245 :                 bool const r = is_key?
    1063              22 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1064             245 :                     h_.on_string_part( {start, size}, total, ec_ );
    1065             223 :                 if(BOOST_JSON_UNLIKELY( !r ))
    1066              22 :                     return fail( cs.begin() );
    1067                 :             }
    1068            1871 :             return maybe_suspend(cs.end(), state::str8, total);
    1069                 :         }
    1070           11609 :         else if(BOOST_JSON_LIKELY(*cs == '\\'))
    1071                 :         {
    1072                 :             // flush unescaped run from input
    1073           11500 :             if(BOOST_JSON_LIKELY(size))
    1074                 :             {
    1075            4250 :                 bool const r = is_key?
    1076            1226 :                     h_.on_key_part( {start, size}, total, ec_ ):
    1077            3554 :                     h_.on_string_part( {start, size}, total, ec_ );
    1078            3766 :                 if(BOOST_JSON_UNLIKELY( !r ))
    1079             484 :                     return fail( cs.begin() );
    1080                 :             }
    1081            7250 : do_str2:
    1082           13681 :             cs = parse_escaped(cs.begin(), total, stack_empty, is_key, allow_bad_utf16);
    1083           12719 :             if(BOOST_JSON_UNLIKELY( incomplete(cs) ))
    1084            5476 :                 return suspend_or_fail(state::str2, total);
    1085                 : 
    1086            7243 :             goto do_str1;
    1087                 :         }
    1088                 :         // illegal control
    1089                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1090             109 :         return fail(cs.begin(), error::syntax, &loc);
    1091                 :     }
    1092                 : 
    1093                 :     {
    1094          119487 :         bool r = is_key?
    1095           84511 :             h_.on_key( {start, size}, total, ec_ ):
    1096           41985 :             h_.on_string( {start, size}, total, ec_ );
    1097                 : 
    1098          115113 :         if(BOOST_JSON_UNLIKELY(!r))
    1099                 :         {
    1100            4318 :             return fail(cs.begin());
    1101                 :         }
    1102                 :     }
    1103                 : 
    1104          110795 :     ++cs;
    1105          110795 :     return cs.begin();
    1106                 : 
    1107            1868 : do_str8:
    1108            1868 :     uint8_t needed = seq_.needed();
    1109            1868 :     if(BOOST_JSON_UNLIKELY( !seq_.append(cs.begin(), cs.remain()) ))
    1110               4 :         return maybe_suspend(cs.end(), state::str8, total);
    1111            1864 :     if(BOOST_JSON_UNLIKELY( !seq_.valid() ))
    1112                 :     {
    1113                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
    1114             210 :         return fail(cs.begin(), error::syntax, &loc);
    1115                 :     }
    1116                 :     {
    1117            1654 :         std::size_t const n = seq_.length();
    1118                 :         bool r;
    1119            1654 :         if(is_key)
    1120                 :         {
    1121               2 :             BOOST_ASSERT(total <= Handler::max_key_size);
    1122               2 :             if(BOOST_JSON_UNLIKELY(n >
    1123                 :                 Handler::max_key_size - total))
    1124                 :             {
    1125                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    1126                 :                     = BOOST_CURRENT_LOCATION;
    1127               1 :                 return fail(cs.begin(), error::key_too_large, &loc);
    1128                 :             }
    1129               1 :             total += n;
    1130               1 :             r = h_.on_key_part( {seq_.data(), n}, total, ec_ );
    1131                 :         }
    1132                 :         else
    1133                 :         {
    1134               1 :             BOOST_ASSERT(total <= Handler::max_string_size);
    1135            1652 :             if(BOOST_JSON_UNLIKELY(n >
    1136                 :                 Handler::max_string_size - total))
    1137                 :             {
    1138                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    1139                 :                     = BOOST_CURRENT_LOCATION;
    1140               1 :                 return fail(cs.begin(), error::string_too_large, &loc);
    1141                 :             }
    1142            1651 :             total += n;
    1143            1651 :             r = h_.on_string_part( {seq_.data(), n}, total, ec_ );
    1144                 :         }
    1145            1451 :         if(BOOST_JSON_UNLIKELY( !r ))
    1146             201 :             return fail( cs.begin() );
    1147                 :     }
    1148            1250 :     cs += needed;
    1149            1250 :     goto do_str1;
    1150                 : }
    1151                 : 
    1152                 : template<class Handler>
    1153                 : template<bool StackEmpty_>
    1154                 : const char*
    1155           13681 : 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           13681 :     constexpr unsigned urc = 0xFFFD; // Unicode replacement character
    1164           13681 :     auto const ev_too_large = is_key?
    1165                 :         error::key_too_large : error::string_too_large;
    1166           13681 :     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           13681 :     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           13681 :     detail::clipped_const_stream cs(p, end_);
    1191           13681 :     cs.clip(temp.max_size());
    1192                 : 
    1193           13681 :     if(! stack_empty && ! st_.empty())
    1194                 :     {
    1195                 :         state st;
    1196            3149 :         st_.pop(st);
    1197            3149 :         switch(st)
    1198                 :         {
    1199                 :         default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
    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            3783 :     while(true)
    1215                 :     {
    1216           14315 :         BOOST_ASSERT( temp.capacity() );
    1217           14315 :         BOOST_ASSERT(*cs == '\\');
    1218           14315 :         ++cs;
    1219           15174 : do_str3:
    1220           15379 :         if(BOOST_JSON_UNLIKELY(! cs))
    1221                 :         {
    1222             562 :             if(BOOST_JSON_LIKELY(! temp.empty()))
    1223                 :             {
    1224               1 :                 BOOST_ASSERT(total <= max_size);
    1225             101 :                 if(BOOST_JSON_UNLIKELY(
    1226                 :                     temp.size() > max_size - total))
    1227                 :                 {
    1228                 :                     BOOST_STATIC_CONSTEXPR source_location loc
    1229                 :                         = BOOST_CURRENT_LOCATION;
    1230               1 :                     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           14817 :         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            1766 :         case 'n':
    1278            1766 :             temp.push_back('\x0a');
    1279            1766 :             ++cs;
    1280            1766 :             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           11689 :         case 'u':
    1290                 :             // utf16 escape
    1291                 :             //
    1292                 :             // fast path only when the buffer
    1293                 :             // is large enough for 2 surrogates
    1294           11689 :             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            5992 :             if(BOOST_JSON_LIKELY(! temp.empty()))
    1465                 :             {
    1466               4 :                 BOOST_ASSERT(total <= max_size);
    1467            1723 :                 if(BOOST_JSON_UNLIKELY(
    1468                 :                     temp.size() > max_size - total))
    1469                 :                 {
    1470                 :                     BOOST_STATIC_CONSTEXPR source_location loc
    1471                 :                         = BOOST_CURRENT_LOCATION;
    1472               1 :                     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           12653 :         if(BOOST_JSON_UNLIKELY( !cs ) || *cs != '\\')
    1696            8870 :             break;
    1697                 :     }
    1698                 : 
    1699            8870 :     if(BOOST_JSON_LIKELY( temp.size() ))
    1700                 :     {
    1701             434 :         BOOST_ASSERT(total <= max_size);
    1702            8870 :         if(BOOST_JSON_UNLIKELY( temp.size() > max_size - total ))
    1703                 :         {
    1704                 :             BOOST_STATIC_CONSTEXPR source_location loc
    1705                 :                 = BOOST_CURRENT_LOCATION;
    1706               1 :             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          109189 : 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          109189 :     detail::const_stream_wrapper cs(p, end_);
    1738                 :     std::size_t size;
    1739          109189 :     if(! stack_empty && ! st_.empty())
    1740                 :     {
    1741                 :         // resume
    1742                 :         state st;
    1743           35058 :         st_.pop(st);
    1744           35058 :         st_.pop(size);
    1745           35058 :         switch(st)
    1746                 :         {
    1747                 :         default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
    1748            1595 :         case state::obj1: goto do_obj1;
    1749             235 :         case state::obj2: goto do_obj2;
    1750           12647 :         case state::obj3: goto do_obj3;
    1751            1690 :         case state::obj4: goto do_obj4;
    1752             251 :         case state::obj5: goto do_obj5;
    1753            1591 :         case state::obj6: goto do_obj6;
    1754           15448 :         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           74131 :     BOOST_ASSERT(*cs == '{');
    1762           74131 :     size = 0;
    1763           74131 :     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           74128 :     --depth_;
    1769           74128 :     if(BOOST_JSON_UNLIKELY(
    1770                 :         ! h_.on_object_begin(ec_)))
    1771            2040 :         return fail(cs.begin());
    1772           70050 :     ++cs;
    1773                 :     // object:
    1774                 :     //     '{' *ws '}'
    1775                 :     //     '{' *ws string *ws ':' *ws value *ws *[ ',' *ws string *ws ':' *ws value *ws ] '}'
    1776           73616 : do_obj1:
    1777           73616 :     cs = detail::count_whitespace(cs.begin(), cs.end());
    1778           73616 :     if(BOOST_JSON_UNLIKELY(! cs))
    1779            1629 :         return maybe_suspend(cs.begin(), state::obj1, size);
    1780           71987 :     if(BOOST_JSON_LIKELY(*cs != '}'))
    1781                 :     {
    1782           69088 :         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           66677 : loop:
    1797           80829 :         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           80828 : do_obj3:
    1805           93475 :         cs = parse_string(cs.begin(), stack_empty, std::true_type(), allow_bad_utf8, allow_bad_utf16);
    1806           90519 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1807           15592 :             return suspend_or_fail(state::obj3, size);
    1808           74927 : do_obj4:
    1809           79088 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1810           79088 :         if(BOOST_JSON_UNLIKELY(! cs))
    1811            1705 :             return maybe_suspend(cs.begin(), state::obj4, size);
    1812           77383 :         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           74458 :         ++cs;
    1827           76049 : do_obj6:
    1828           76049 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1829           76049 :         if(BOOST_JSON_UNLIKELY(! cs))
    1830            1622 :             return maybe_suspend(cs.begin(), state::obj6, size);
    1831           74427 : do_obj7:
    1832           89875 :         cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
    1833           82526 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1834           23593 :             return suspend_or_fail(state::obj7, size);
    1835           58933 : do_obj8:
    1836           61195 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1837           61195 :         if(BOOST_JSON_UNLIKELY(! cs))
    1838             441 :             return maybe_suspend(cs.begin(), state::obj8, size);
    1839           60754 :         if(BOOST_JSON_LIKELY(*cs == ','))
    1840                 :         {
    1841           17792 :             ++cs;
    1842           19707 : do_obj9:
    1843           19707 :             cs = detail::count_whitespace(cs.begin(), cs.end());
    1844           19707 :             if(BOOST_JSON_UNLIKELY(! cs))
    1845             690 :                 return maybe_suspend(cs.begin(), state::obj9, size);
    1846                 : 
    1847                 :             // loop for next element
    1848           19017 :             if(BOOST_JSON_LIKELY(*cs == '\x22'))
    1849           14152 :                 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           42962 :         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           46757 :     if(BOOST_JSON_UNLIKELY(
    1882                 :         ! h_.on_object_end(size, ec_)))
    1883            1502 :         return fail(cs.begin());
    1884           43714 :     ++depth_;
    1885           43714 :     ++cs;
    1886           43714 :     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           26348 : 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           26348 :     detail::const_stream_wrapper cs(p, end_);
    1907                 :     std::size_t size;
    1908           26348 :     if(! stack_empty && ! st_.empty())
    1909                 :     {
    1910                 :         // resume
    1911                 :         state st;
    1912            5730 :         st_.pop(st);
    1913            5730 :         st_.pop(size);
    1914            5730 :         switch(st)
    1915                 :         {
    1916                 :         default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
    1917            1052 :         case state::arr1: goto do_arr1;
    1918             384 :         case state::arr2: goto do_arr2;
    1919            2938 :         case state::arr3: goto do_arr3;
    1920             391 :         case state::arr4: goto do_arr4;
    1921             671 :         case state::arr5: goto do_arr5;
    1922             294 :         case state::arr6: goto do_arr6;
    1923                 :         }
    1924                 :     }
    1925           20618 :     BOOST_ASSERT(*cs == '[');
    1926           20618 :     size = 0;
    1927           20618 :     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           20584 :     --depth_;
    1933           20584 :     if(BOOST_JSON_UNLIKELY(
    1934                 :         ! h_.on_array_begin(ec_)))
    1935             812 :         return fail(cs.begin());
    1936           18966 :     ++cs;
    1937                 :     // array:
    1938                 :     //     '[' *ws ']'
    1939                 :     //     '[' *ws value *ws *[ ',' *ws value *ws ] ']'
    1940           21551 : do_arr1:
    1941           21551 :     cs = detail::count_whitespace(cs.begin(), cs.end());
    1942           21551 :     if(BOOST_JSON_UNLIKELY(! cs))
    1943            1073 :         return maybe_suspend(cs.begin(), state::arr1, size);
    1944           20478 :     if(BOOST_JSON_LIKELY(*cs != ']'))
    1945                 :     {
    1946           18730 : loop:
    1947           26193 :         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           24404 :         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           24403 : do_arr3:
    1963                 :         // array is not empty, value required
    1964           27341 :         cs = parse_value(cs.begin(), stack_empty, allow_comments, allow_trailing, allow_bad_utf8, allow_bad_utf16);
    1965           24710 :         if(BOOST_JSON_UNLIKELY(incomplete(cs)))
    1966            9052 :             return suspend_or_fail(state::arr3, size);
    1967           15658 : do_arr4:
    1968           17279 :         cs = detail::count_whitespace(cs.begin(), cs.end());
    1969           17279 :         if(BOOST_JSON_UNLIKELY(! cs))
    1970             500 :             return maybe_suspend(cs.begin(), state::arr4, size);
    1971           16779 :         if(BOOST_JSON_LIKELY(*cs == ','))
    1972                 :         {
    1973            9176 :             ++cs;
    1974            9847 : do_arr5:
    1975            9847 :             cs = detail::count_whitespace(cs.begin(), cs.end());
    1976            9847 :             if(BOOST_JSON_UNLIKELY(! cs))
    1977             701 :                 return maybe_suspend(cs.begin(), state::arr5, size);
    1978                 :             // loop for next element
    1979            9146 :             if(! allow_trailing || *cs != ']')
    1980            7463 :                 goto loop;
    1981                 :         }
    1982            7603 :         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            9065 :     if(BOOST_JSON_UNLIKELY(
    1999                 :         ! h_.on_array_end(size, ec_)))
    2000             547 :         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        10515990 : 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        10515990 :     constexpr bool precise_parsing = mode == number_precision::precise;
    2018        10515990 :     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        10515990 :     bool const negative = first == '-';
    2025        10515990 :     bool const zero_first = first == '0';
    2026        10515990 :     bool const nonzero_first = first == '+';
    2027        10515990 :     detail::const_stream_wrapper cs(p, end_);
    2028                 :     number num;
    2029        10515990 :     const char* begin = cs.begin();
    2030        10515990 :     if(stack_empty || st_.empty())
    2031                 :     {
    2032         2089971 :         num.bias = 0;
    2033         2089971 :         num.exp = 0;
    2034         2089971 :         num.frac = false;
    2035         2089971 :         num_buf_.clear();
    2036                 : 
    2037                 :         //----------------------------------
    2038                 :         //
    2039                 :         // '-'
    2040                 :         // leading minus sign
    2041                 :         //
    2042         2089971 :         BOOST_ASSERT(cs);
    2043                 :         if(negative)
    2044           25185 :             ++cs;
    2045                 : 
    2046         2089971 :         num.neg = negative;
    2047         2089971 :         num.frac = false;
    2048         2089971 :         num.exp = 0;
    2049         2089971 :         num.bias = 0;
    2050                 : 
    2051                 :         // fast path
    2052         2089971 :         if( cs.remain() >= 16 + 1 + 16 ) // digits . digits
    2053                 :         {
    2054                 :             int n1;
    2055                 : 
    2056            9989 :             if( nonzero_first ||
    2057            9989 :                 (negative && *cs != '0') )
    2058                 :             {
    2059         2007319 :                 n1 = detail::count_digits( cs.begin() );
    2060         2007319 :                 BOOST_ASSERT(n1 >= 0 && n1 <= 16);
    2061                 : 
    2062            1837 :                 if( negative && n1 == 0 && opt_.allow_infinity_and_nan )
    2063                 :                 {
    2064               9 :                     return parse_literal(
    2065                 :                         p - 1,
    2066               8 :                         detail::literals_c<detail::literals::neg_infinity>());
    2067                 :                 }
    2068                 : 
    2069            1828 :                 if( ! nonzero_first && n1 == 0 )
    2070                 :                 {
    2071                 :                     // digit required
    2072                 :                     BOOST_STATIC_CONSTEXPR source_location loc
    2073                 :                         = BOOST_CURRENT_LOCATION;
    2074               2 :                     return fail(cs.begin(), error::syntax, &loc);
    2075                 :                 }
    2076                 : 
    2077                 :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2078         2006460 :                     num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
    2079                 :                 else
    2080             848 :                     num.mant = 0;
    2081                 : 
    2082         2007308 :                 cs += n1;
    2083                 : 
    2084                 :                 // integer or floating-point with
    2085                 :                 // >= 16 leading digits
    2086         2007308 :                 if( n1 == 16 )
    2087                 :                 {
    2088         2001425 :                     goto do_num2;
    2089                 :                 }
    2090                 :             }
    2091                 :             else
    2092                 :             {
    2093                 :                 // 0. floating-point or 0e integer
    2094           21187 :                 num.mant = 0;
    2095           21187 :                 n1 = 0;
    2096           21187 :                 ++cs;
    2097                 :             }
    2098                 : 
    2099                 :             {
    2100           27070 :                 const char c = *cs;
    2101           27070 :                 if(c != '.')
    2102                 :                 {
    2103            9871 :                     if((c | 32) == 'e')
    2104                 :                     {
    2105            6576 :                         ++cs;
    2106            6576 :                         goto do_exp1;
    2107                 :                     }
    2108                 :                     BOOST_IF_CONSTEXPR( negative && !no_parsing )
    2109              20 :                         num.mant = ~num.mant + 1;
    2110            3295 :                     goto finish_signed;
    2111                 :                 }
    2112                 :             }
    2113                 : 
    2114                 :             // floating-point number
    2115                 : 
    2116           17199 :             ++cs;
    2117                 : 
    2118           17199 :             int n2 = detail::count_digits( cs.begin() );
    2119           17199 :             BOOST_ASSERT(n2 >= 0 && n2 <= 16);
    2120                 : 
    2121           17199 :             if( n2 == 0 )
    2122                 :             {
    2123                 :                 // digit required
    2124                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    2125                 :                     = BOOST_CURRENT_LOCATION;
    2126               3 :                 return fail(cs.begin(), error::syntax, &loc);
    2127                 :             }
    2128                 : 
    2129                 :             // floating-point mantissa overflow
    2130           17196 :             if( n1 + n2 >= 19 )
    2131                 :             {
    2132             122 :                 goto do_num7;
    2133                 :             }
    2134                 : 
    2135                 :             BOOST_IF_CONSTEXPR( !no_parsing )
    2136           12855 :                 num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
    2137                 : 
    2138           17074 :             BOOST_ASSERT(num.bias == 0);
    2139                 : 
    2140           17074 :             num.bias -= n2;
    2141                 : 
    2142           17074 :             cs += n2;
    2143                 : 
    2144           17074 :             char ch = *cs;
    2145                 : 
    2146           17074 :             if( (ch | 32) == 'e' )
    2147                 :             {
    2148             110 :                 ++cs;
    2149             110 :                 goto do_exp1;
    2150                 :             }
    2151           16964 :             else if( ch >= '0' && ch <= '9' )
    2152                 :             {
    2153           10017 :                 goto do_num8;
    2154                 :             }
    2155                 : 
    2156            6947 :             goto finish_dub;
    2157                 :         }
    2158                 :     }
    2159                 :     else
    2160                 :     {
    2161         8426019 :         num = num_;
    2162                 :         state st;
    2163         8426019 :         st_.pop(st);
    2164         8426019 :         switch(st)
    2165                 :         {
    2166                 :         default: BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE
    2167             603 :         case state::num1: goto do_num1;
    2168            6460 :         case state::num2: goto do_num2;
    2169         4195112 :         case state::num3: goto do_num3;
    2170              52 :         case state::num4: goto do_num4;
    2171            4537 :         case state::num5: goto do_num5;
    2172             668 :         case state::num6: goto do_num6;
    2173             618 :         case state::num7: goto do_num7;
    2174         4205248 :         case state::num8: goto do_num8;
    2175             477 :         case state::exp1: goto do_exp1;
    2176             139 :         case state::exp2: goto do_exp2;
    2177           12105 :         case state::exp3: goto do_exp3;
    2178                 :         }
    2179                 :     }
    2180                 : 
    2181                 :     //----------------------------------
    2182                 :     //
    2183                 :     // DIGIT
    2184                 :     // first digit
    2185                 :     //
    2186           62068 : do_num1:
    2187           15799 :     if(zero_first || nonzero_first ||
    2188           15799 :         BOOST_JSON_LIKELY(cs))
    2189                 :     {
    2190           61345 :         char const c = *cs;
    2191                 :         if(zero_first)
    2192                 :         {
    2193            9726 :             ++cs;
    2194            9726 :             num.mant = 0;
    2195            9726 :             goto do_num6;
    2196                 :         }
    2197           15076 :         else if(nonzero_first || BOOST_JSON_LIKELY(
    2198                 :             c >= '1' && c <= '9'))
    2199                 :         {
    2200           42790 :             ++cs;
    2201           42790 :             num.mant = c - '0';
    2202                 :         }
    2203            8829 :         else if(BOOST_JSON_UNLIKELY(
    2204                 :             c == '0'))
    2205                 :         {
    2206            7634 :             ++cs;
    2207            7634 :             num.mant = 0;
    2208            7634 :             goto do_num6;
    2209                 :         }
    2210            1195 :         else if( (negative || num.neg) && opt_.allow_infinity_and_nan )
    2211                 :         {
    2212            1007 :             st_.push(state::lit1);
    2213            1007 :             cur_lit_ = literal_index(detail::literals::neg_infinity);
    2214            1007 :             lit_offset_ = 1;
    2215            1007 :             return parse_literal(
    2216             961 :                 cs.begin(), detail::literals_c<detail::literals::resume>() );
    2217                 :         }
    2218                 :         else
    2219                 :         {
    2220                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2221                 :                 = BOOST_CURRENT_LOCATION;
    2222             188 :             return fail(cs.begin(), error::syntax, &loc);
    2223                 :         }
    2224                 :     }
    2225                 :     else
    2226                 :     {
    2227             723 :         if(BOOST_JSON_UNLIKELY(
    2228                 :             ! h_.on_number_part(
    2229                 :                 {begin, cs.used(begin)}, ec_)))
    2230              60 :             return fail(cs.begin());
    2231                 : 
    2232                 :         BOOST_IF_CONSTEXPR( precise_parsing )
    2233 MIS           0 :             num_buf_.append( begin, cs.used(begin) );
    2234 HIT         603 :         return maybe_suspend(
    2235             603 :             cs.begin(), state::num1, num);
    2236                 :     }
    2237                 : 
    2238                 :     //----------------------------------
    2239                 :     //
    2240                 :     // 1*DIGIT
    2241                 :     // significant digits left of decimal
    2242                 :     //
    2243         2050675 : do_num2:
    2244         2044417 :     if(negative || (!stack_empty && num.neg))
    2245                 :     {
    2246           22400 :         for(;;)
    2247                 :         {
    2248           30225 :             if(BOOST_JSON_UNLIKELY(! cs))
    2249                 :             {
    2250            1921 :                 if(BOOST_JSON_UNLIKELY(more_))
    2251                 :                 {
    2252            1469 :                     if(BOOST_JSON_UNLIKELY(
    2253                 :                         ! h_.on_number_part(
    2254                 :                             {begin, cs.used(begin)}, ec_)))
    2255              69 :                         return fail(cs.begin());
    2256                 : 
    2257                 :                     BOOST_IF_CONSTEXPR( precise_parsing )
    2258 MIS           0 :                         num_buf_.append( begin, cs.used(begin) );
    2259 HIT        1331 :                     return suspend(cs.begin(), state::num2, num);
    2260                 :                 }
    2261             452 :                 goto finish_int;
    2262                 :             }
    2263           28304 :             char const c = *cs;
    2264           28304 :             if(BOOST_JSON_LIKELY(
    2265                 :                 c >= '0' && c <= '9'))
    2266                 :             {
    2267           23223 :                 ++cs;
    2268                 :                 //              9223372036854775808 INT64_MIN
    2269           23223 :                 if( num.mant  > 922337203685477580 || (
    2270           22508 :                     num.mant == 922337203685477580 && c > '8'))
    2271                 :                     break;
    2272                 :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2273           22141 :                     num.mant = 10 * num.mant + ( c - '0' );
    2274           22400 :                 continue;
    2275                 :             }
    2276            5081 :             goto do_num6; // [.eE]
    2277                 :         }
    2278                 :     }
    2279                 :     else
    2280                 :     {
    2281         6889563 :         for(;;)
    2282                 :         {
    2283         8932413 :             if(BOOST_JSON_UNLIKELY(! cs))
    2284                 :             {
    2285            6588 :                 if(BOOST_JSON_UNLIKELY(more_))
    2286                 :                 {
    2287            5975 :                     if(BOOST_JSON_UNLIKELY(
    2288                 :                         ! h_.on_number_part(
    2289                 :                             {begin, cs.used(begin)}, ec_)))
    2290             426 :                         return fail(cs.begin());
    2291                 : 
    2292                 :                     BOOST_IF_CONSTEXPR( precise_parsing )
    2293 MIS           0 :                         num_buf_.append( begin, cs.used(begin) );
    2294 HIT        5129 :                     return suspend(cs.begin(), state::num2, num);
    2295                 :                 }
    2296             613 :                 goto finish_int;
    2297                 :             }
    2298         8925825 :             char const c = *cs;
    2299         8925825 :             if(BOOST_JSON_LIKELY(
    2300                 :                 c >= '0' && c <= '9'))
    2301                 :             {
    2302         6893607 :                 ++cs;
    2303                 :                 //              18446744073709551615 UINT64_MAX
    2304         6893607 :                 if( num.mant  > 1844674407370955161 || (
    2305         6889985 :                     num.mant == 1844674407370955161 && c > '5'))
    2306                 :                     break;
    2307                 :                 BOOST_IF_CONSTEXPR( !no_parsing )
    2308         6883965 :                     num.mant = 10 * num.mant + ( c - '0' );
    2309                 :             }
    2310                 :             else
    2311                 :             {
    2312         2032218 :                 goto do_num6; // [.eE]
    2313                 :             }
    2314                 :         }
    2315                 :     }
    2316            4867 :     ++num.bias;
    2317                 : 
    2318                 :     //----------------------------------
    2319                 :     //
    2320                 :     // 1*DIGIT
    2321                 :     // non-significant digits left of decimal
    2322                 :     //
    2323         4199979 : do_num3:
    2324      4294978560 :     for(;;)
    2325                 :     {
    2326      4299178539 :         if(BOOST_JSON_UNLIKELY(! cs))
    2327                 :         {
    2328         4195839 :             if(BOOST_JSON_UNLIKELY(more_))
    2329                 :             {
    2330         4195206 :                 if(BOOST_JSON_UNLIKELY(
    2331                 :                     ! h_.on_number_part(
    2332                 :                         {begin, cs.used(begin)}, ec_)))
    2333              47 :                     return fail(cs.begin());
    2334                 : 
    2335                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2336 MIS           0 :                     num_buf_.append( begin, cs.used(begin) );
    2337 HIT     4195112 :                 return suspend(cs.begin(), state::num3, num);
    2338                 :             }
    2339             633 :             goto finish_dub;
    2340                 :         }
    2341      4294982700 :         char const c = *cs;
    2342      4294982700 :         if(BOOST_JSON_UNLIKELY(
    2343                 :             c >= '0' && c <= '9'))
    2344                 :         {
    2345      4294978561 :             if(BOOST_JSON_UNLIKELY( num.bias + 1 == INT_MAX ))
    2346                 :             {
    2347                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    2348                 :                     = BOOST_CURRENT_LOCATION;
    2349               1 :                 return fail(cs.begin(), error::exponent_overflow, &loc);
    2350                 :             }
    2351      4294978560 :             ++cs;
    2352      4294978560 :             ++num.bias;
    2353                 :         }
    2354            4139 :         else if(BOOST_JSON_LIKELY(
    2355                 :             c == '.'))
    2356                 :         {
    2357            2028 :             ++cs;
    2358            2028 :             break;
    2359                 :         }
    2360            2111 :         else if((c | 32) == 'e')
    2361                 :         {
    2362             762 :             ++cs;
    2363             762 :             goto do_exp1;
    2364                 :         }
    2365                 :         else
    2366                 :         {
    2367            1349 :             goto finish_dub;
    2368                 :         }
    2369                 :     }
    2370                 : 
    2371                 :     //----------------------------------
    2372                 :     //
    2373                 :     // DIGIT
    2374                 :     // first non-significant digit
    2375                 :     // to the right of decimal
    2376                 :     //
    2377            2080 : do_num4:
    2378                 :     {
    2379            2080 :         if(BOOST_JSON_UNLIKELY(! cs))
    2380                 :         {
    2381              64 :             if(BOOST_JSON_UNLIKELY(
    2382                 :                 ! h_.on_number_part(
    2383                 :                     {begin, cs.used(begin)}, ec_)))
    2384               6 :                 return fail(cs.begin());
    2385                 : 
    2386                 :             BOOST_IF_CONSTEXPR( precise_parsing )
    2387 MIS           0 :                 num_buf_.append( begin, cs.used(begin) );
    2388 HIT          52 :             return maybe_suspend(
    2389              52 :                 cs.begin(), state::num4, num);
    2390                 :         }
    2391            2016 :         char const c = *cs;
    2392            2016 :         if(BOOST_JSON_LIKELY(
    2393                 :             //static_cast<unsigned char>(c - '0') < 10))
    2394                 :             c >= '0' && c <= '9'))
    2395                 :         {
    2396            1949 :             ++cs;
    2397                 :         }
    2398                 :         else
    2399                 :         {
    2400                 :             // digit required
    2401                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2402                 :                 = BOOST_CURRENT_LOCATION;
    2403              67 :             return fail(cs.begin(), error::syntax, &loc);
    2404                 :         }
    2405                 :     }
    2406                 : 
    2407                 :     //----------------------------------
    2408                 :     //
    2409                 :     // 1*DIGIT
    2410                 :     // non-significant digits
    2411                 :     // to the right of decimal
    2412                 :     //
    2413         2013470 : do_num5:
    2414        37889832 :     for(;;)
    2415                 :     {
    2416        39903302 :         if(BOOST_JSON_UNLIKELY(! cs))
    2417                 :         {
    2418            6112 :             if(BOOST_JSON_UNLIKELY(more_))
    2419                 :             {
    2420            4577 :                 if(BOOST_JSON_UNLIKELY(
    2421                 :                     ! h_.on_number_part(
    2422                 :                         {begin, cs.used(begin)}, ec_)))
    2423              20 :                     return fail(cs.begin());
    2424                 : 
    2425                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2426 MIS           0 :                     num_buf_.append( begin, cs.used(begin) );
    2427 HIT        4537 :                 return suspend(cs.begin(), state::num5, num);
    2428                 :             }
    2429            1535 :             goto finish_dub;
    2430                 :         }
    2431        39897190 :         char const c = *cs;
    2432        39897190 :         if(BOOST_JSON_LIKELY(
    2433                 :             c >= '0' && c <= '9'))
    2434                 :         {
    2435        37889832 :             ++cs;
    2436                 :         }
    2437         2007358 :         else if((c | 32) == 'e')
    2438                 :         {
    2439         2003236 :             ++cs;
    2440         2003236 :             goto do_exp1;
    2441                 :         }
    2442                 :         else
    2443                 :         {
    2444            4122 :             goto finish_dub;
    2445                 :         }
    2446                 :     }
    2447                 : 
    2448                 :     //----------------------------------
    2449                 :     //
    2450                 :     // [.eE]
    2451                 :     //
    2452         2055327 : do_num6:
    2453                 :     {
    2454         2055327 :         if(BOOST_JSON_UNLIKELY(! cs))
    2455                 :         {
    2456             800 :             if(BOOST_JSON_UNLIKELY(more_))
    2457                 :             {
    2458             753 :                 if(BOOST_JSON_UNLIKELY(
    2459                 :                     ! h_.on_number_part(
    2460                 :                         {begin, cs.used(begin)}, ec_)))
    2461              42 :                     return fail(cs.begin());
    2462                 : 
    2463                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2464               2 :                     num_buf_.append( begin, cs.used(begin) );
    2465             669 :                 return suspend(cs.begin(), state::num6, num);
    2466                 :             }
    2467              47 :             goto finish_int;
    2468                 :         }
    2469         2054527 :         char const c = *cs;
    2470         2054527 :         if(BOOST_JSON_LIKELY(
    2471                 :             c == '.'))
    2472                 :         {
    2473         2016099 :             ++cs;
    2474                 :         }
    2475           38428 :         else if((c | 32) == 'e')
    2476                 :         {
    2477            9153 :             ++cs;
    2478            9153 :             goto do_exp1;
    2479                 :         }
    2480                 :         else
    2481                 :         {
    2482           29275 :             goto finish_int;
    2483                 :         }
    2484                 :     }
    2485                 : 
    2486                 :     //----------------------------------
    2487                 :     //
    2488                 :     // DIGIT
    2489                 :     // first significant digit
    2490                 :     // to the right of decimal
    2491                 :     //
    2492         2016839 : do_num7:
    2493                 :     {
    2494         2016839 :         if(BOOST_JSON_UNLIKELY(! cs))
    2495                 :         {
    2496             693 :             if(BOOST_JSON_UNLIKELY(more_))
    2497                 :             {
    2498             689 :                 if(BOOST_JSON_UNLIKELY(
    2499                 :                     ! h_.on_number_part(
    2500                 :                         {begin, cs.used(begin)}, ec_)))
    2501              35 :                     return fail(cs.begin());
    2502                 : 
    2503                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2504 MIS           0 :                     num_buf_.append( begin, cs.used(begin) );
    2505 HIT         619 :                 return suspend(cs.begin(), state::num7, num);
    2506                 :             }
    2507                 :             // digit required
    2508                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2509                 :                 = BOOST_CURRENT_LOCATION;
    2510               4 :             return fail(cs.begin(), error::syntax, &loc);
    2511                 :         }
    2512         2016146 :         char const c = *cs;
    2513         2016146 :         if(BOOST_JSON_UNLIKELY(
    2514                 :             c < '0' || c > '9'))
    2515                 :         {
    2516                 :             // digit required
    2517                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2518                 :                 = BOOST_CURRENT_LOCATION;
    2519             169 :             return fail(cs.begin(), error::syntax, &loc);
    2520                 :         }
    2521                 :     }
    2522                 : 
    2523                 :     //----------------------------------
    2524                 :     //
    2525                 :     // 1*DIGIT
    2526                 :     // significant digits
    2527                 :     // to the right of decimal
    2528                 :     //
    2529         6228742 : do_num8:
    2530      4298245220 :     for(;;)
    2531                 :     {
    2532      4304476462 :         if(BOOST_JSON_UNLIKELY(! cs))
    2533                 :         {
    2534         4207120 :             if(BOOST_JSON_UNLIKELY(more_))
    2535                 :             {
    2536         4205384 :                 if(BOOST_JSON_UNLIKELY(
    2537                 :                     ! h_.on_number_part(
    2538                 :                         {begin, cs.used(begin)}, ec_)))
    2539              67 :                     return fail(cs.begin());
    2540                 : 
    2541                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2542               2 :                     num_buf_.append( begin, cs.used(begin) );
    2543         4205249 :                 return suspend(cs.begin(), state::num8, num);
    2544                 :             }
    2545            1736 :             goto finish_dub;
    2546                 :         }
    2547      4300269342 :         char const c = *cs;
    2548      4300269342 :         if(BOOST_JSON_LIKELY(
    2549                 :             c >= '0' && c <= '9'))
    2550                 :         {
    2551      4300252205 :             ++cs;
    2552      4300247112 :             if(!no_parsing && BOOST_JSON_LIKELY(
    2553                 :                 num.mant <= 9007199254740991)) // 2^53-1
    2554                 :             {
    2555      4298245221 :                 if(BOOST_JSON_UNLIKELY( num.bias - 1 == INT_MIN ))
    2556                 :                 {
    2557                 :                     BOOST_STATIC_CONSTEXPR source_location loc
    2558                 :                         = BOOST_CURRENT_LOCATION;
    2559               1 :                     return fail(cs.begin(), error::exponent_overflow, &loc);
    2560                 :                 }
    2561      4298245220 :                 --num.bias;
    2562      4298245220 :                 num.mant = 10 * num.mant + ( c - '0' );
    2563                 :             }
    2564                 :             else
    2565                 :             {
    2566         2006984 :                 goto do_num5;
    2567                 :             }
    2568                 :         }
    2569           17137 :         else if((c | 32) == 'e')
    2570                 :         {
    2571           11134 :             ++cs;
    2572           11134 :             goto do_exp1;
    2573                 :         }
    2574                 :         else
    2575                 :         {
    2576            6003 :             goto finish_dub;
    2577                 :         }
    2578                 :     }
    2579                 : 
    2580                 :     //----------------------------------
    2581                 :     //
    2582                 :     // *[+-]
    2583                 :     //
    2584         2031448 : do_exp1:
    2585         2031448 :     if(BOOST_JSON_UNLIKELY(! cs))
    2586                 :     {
    2587             575 :         if(BOOST_JSON_UNLIKELY(
    2588                 :             ! h_.on_number_part(
    2589                 :                 {begin, cs.used(begin)}, ec_)))
    2590              49 :             return fail(cs.begin());
    2591                 : 
    2592                 :         BOOST_IF_CONSTEXPR( precise_parsing )
    2593 MIS           0 :             num_buf_.append( begin, cs.used(begin) );
    2594 HIT         477 :         return maybe_suspend(
    2595             477 :             cs.begin(), state::exp1, num);
    2596                 :     }
    2597         2030873 :     if(*cs == '+')
    2598                 :     {
    2599            2364 :         ++cs;
    2600                 :     }
    2601         2028509 :     else if(*cs == '-')
    2602                 :     {
    2603         1001936 :         ++cs;
    2604         1001936 :         num.frac = true;
    2605                 :     }
    2606                 : 
    2607                 :     //----------------------------------
    2608                 :     //
    2609                 :     // DIGIT
    2610                 :     // first digit of the exponent
    2611                 :     //
    2612         1026573 : do_exp2:
    2613                 :     {
    2614         2031012 :         if(BOOST_JSON_UNLIKELY(! cs))
    2615                 :         {
    2616             188 :             if(BOOST_JSON_UNLIKELY(more_))
    2617                 :             {
    2618             179 :                 if(BOOST_JSON_UNLIKELY(
    2619                 :                     ! h_.on_number_part(
    2620                 :                         {begin, cs.used(begin)}, ec_)))
    2621              20 :                     return fail(cs.begin());
    2622                 : 
    2623                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2624 MIS           0 :                     num_buf_.append( begin, cs.used(begin) );
    2625 HIT         139 :                 return suspend(cs.begin(), state::exp2, num);
    2626                 :             }
    2627                 :             // digit required
    2628                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2629                 :                 = BOOST_CURRENT_LOCATION;
    2630               9 :             return fail(cs.begin(), error::syntax, &loc);
    2631                 :         }
    2632         2030824 :         char const c = *cs;
    2633         2030824 :         if(BOOST_JSON_UNLIKELY(
    2634                 :             c < '0' || c > '9'))
    2635                 :         {
    2636                 :             // digit required
    2637                 :             BOOST_STATIC_CONSTEXPR source_location loc
    2638                 :                 = BOOST_CURRENT_LOCATION;
    2639             508 :             return fail(cs.begin(), error::syntax, &loc);
    2640                 :         }
    2641         2030316 :         ++cs;
    2642         2030316 :         num.exp = c - '0';
    2643                 :     }
    2644                 : 
    2645                 :     //----------------------------------
    2646                 :     //
    2647                 :     // 1*DIGIT
    2648                 :     // subsequent digits in the exponent
    2649                 :     //
    2650         2042421 : do_exp3:
    2651         5468163 :     for(;;)
    2652                 :     {
    2653         7510584 :         if(BOOST_JSON_UNLIKELY(! cs))
    2654                 :         {
    2655         2020838 :             if(BOOST_JSON_UNLIKELY(more_))
    2656                 :             {
    2657           12277 :                 if(BOOST_JSON_UNLIKELY(
    2658                 :                     ! h_.on_number_part(
    2659                 :                         {begin, cs.used(begin)}, ec_)))
    2660              86 :                     return fail(cs.begin());
    2661                 : 
    2662                 :                 BOOST_IF_CONSTEXPR( precise_parsing )
    2663 MIS           0 :                     num_buf_.append( begin, cs.used(begin) );
    2664 HIT       12105 :                 return suspend(cs.begin(), state::exp3, num);
    2665                 :             }
    2666                 :         }
    2667                 :         else
    2668                 :         {
    2669         5489746 :             char const c = *cs;
    2670         5489746 :             if(BOOST_JSON_LIKELY( c >= '0' && c <= '9' ))
    2671                 :             {
    2672         5468163 :                 if(BOOST_JSON_UNLIKELY(
    2673                 :                 //              2147483647 INT_MAX
    2674                 :                     num.exp  >  214748364 ||
    2675                 :                     (num.exp == 214748364 && c > '7')
    2676                 :                 ))
    2677            3855 :                     num.exp = INT_MAX;
    2678                 :                 else BOOST_IF_CONSTEXPR( !no_parsing )
    2679         4923456 :                     num.exp = 10 * num.exp + ( c - '0' );
    2680                 : 
    2681         5468163 :                 ++cs;
    2682         5468163 :                 continue;
    2683                 :             }
    2684                 :         }
    2685         2030144 :         BOOST_ASSERT(num.exp >= 0);
    2686         2030144 :         if ( num.frac )
    2687                 :         {
    2688         1001800 :             if(BOOST_JSON_UNLIKELY( num.bias < (INT_MIN + num.exp) ))
    2689                 :             {
    2690                 :                 // if exponent overflowed, bias is a very large negative
    2691                 :                 // number, and mantissa isn't zero, then we cannot parse the
    2692                 :                 // number correctly
    2693              92 :                 if(BOOST_JSON_UNLIKELY(
    2694                 :                     (num.exp == INT_MAX) &&
    2695                 :                     (num.bias < 0) &&
    2696                 :                     (num.exp + num.bias < 308) &&
    2697                 :                     num.mant ))
    2698                 :                 {
    2699                 :                     BOOST_STATIC_CONSTEXPR source_location loc
    2700                 :                         = BOOST_CURRENT_LOCATION;
    2701               1 :                     return fail(cs.begin(), error::exponent_overflow, &loc);
    2702                 :                 }
    2703                 : 
    2704              91 :                 num.bias = 0;
    2705              91 :                 num.exp = INT_MAX;
    2706                 :             }
    2707                 :         }
    2708         1028344 :         else if (BOOST_JSON_UNLIKELY( num.bias > (INT_MAX - num.exp) ))
    2709                 :         {
    2710                 :             // if exponent overflowed, bias is a very large positive number,
    2711                 :             // and mantissa isn't zero, then we cannot parse the
    2712                 :             // number correctly
    2713             194 :             if(BOOST_JSON_UNLIKELY(
    2714                 :                 (num.exp == INT_MAX) &&
    2715                 :                 (num.bias > 0) &&
    2716                 :                 (num.exp - num.bias < 308) &&
    2717                 :                 num.mant ))
    2718                 :             {
    2719                 :                 BOOST_STATIC_CONSTEXPR source_location loc
    2720                 :                     = BOOST_CURRENT_LOCATION;
    2721               1 :                 return fail(cs.begin(), error::exponent_overflow, &loc);
    2722                 :             }
    2723                 : 
    2724             193 :             num.bias = 0;
    2725             193 :             num.exp = INT_MAX;
    2726                 :         }
    2727         2030142 :         goto finish_dub;
    2728                 :     }
    2729                 : 
    2730           30387 : finish_int:
    2731           28458 :     if(negative || (!stack_empty && num.neg))
    2732                 :     {
    2733            2531 :         if(BOOST_JSON_UNLIKELY(
    2734                 :             ! h_.on_int64(static_cast<
    2735                 :                 int64_t>(~num.mant + 1), {begin, cs.used(begin)}, ec_)))
    2736             310 :             return fail(cs.begin());
    2737            1913 :         return cs.begin();
    2738                 :     }
    2739           27856 :     if(num.mant <= INT64_MAX)
    2740                 :     {
    2741           27555 : finish_signed:
    2742           30830 :         if(BOOST_JSON_UNLIKELY(
    2743                 :             ! h_.on_int64(static_cast<
    2744                 :                 int64_t>(num.mant), {begin, cs.used(begin)}, ec_)))
    2745            2267 :             return fail(cs.begin());
    2746           26303 :         return cs.begin();
    2747                 :     }
    2748             321 :     if(BOOST_JSON_UNLIKELY(
    2749                 :         ! h_.on_uint64(num.mant, {begin, cs.used(begin)}, ec_)))
    2750              35 :         return fail(cs.begin());
    2751             254 :     return cs.begin();
    2752         2052467 : finish_dub:
    2753                 :     double d;
    2754         2052467 :     std::size_t const size = cs.used(begin);
    2755         2052467 :     BOOST_ASSERT( !num_buf_.size() || precise_parsing );
    2756                 :     BOOST_IF_CONSTEXPR( precise_parsing )
    2757                 :     {
    2758         1000052 :         char const* data = begin;
    2759         1000052 :         std::size_t full_size = size;
    2760                 :          // if we previously suspended or if the current input ends with the
    2761                 :          // number, we need to copy the current part of the number to the
    2762                 :          // temporary buffer
    2763         1000052 :         if(BOOST_JSON_UNLIKELY( num_buf_.size() ))
    2764                 :         {
    2765               1 :             data = num_buf_.append( begin, size );
    2766               1 :             full_size = num_buf_.size();
    2767                 :         }
    2768         1000052 :         auto const err = detail::charconv::from_chars(
    2769                 :             data, data + full_size, d );
    2770         1000052 :         BOOST_ASSERT( err.ec != std::errc::invalid_argument );
    2771         1000052 :         BOOST_ASSERT( err.ptr == data + full_size );
    2772                 :         (void)err;
    2773                 :     }
    2774                 :     else BOOST_IF_CONSTEXPR( no_parsing )
    2775            9258 :         d = 0;
    2776                 :     else
    2777         1043157 :         d = detail::dec_to_float(
    2778                 :             num.mant,
    2779          541045 :             num.bias + (num.frac ?
    2780          502112 :                 -num.exp : num.exp),
    2781         1043157 :             num.neg);
    2782         2052467 :     if(BOOST_JSON_UNLIKELY(
    2783                 :         ! h_.on_double(d, {begin, size}, ec_)))
    2784            1935 :         return fail(cs.begin());
    2785         2048597 :     return cs.begin();
    2786                 : }
    2787                 : 
    2788                 : //----------------------------------------------------------
    2789                 : 
    2790                 : template<class Handler>
    2791                 : template<class... Args>
    2792         2164987 : basic_parser<Handler>::
    2793                 : basic_parser(
    2794                 :     parse_options const& opt,
    2795                 :     Args&&... args)
    2796         2164978 :     : h_(std::forward<Args>(args)...)
    2797         2164987 :     , opt_(opt)
    2798                 : {
    2799         2164987 : }
    2800                 : 
    2801                 : //----------------------------------------------------------
    2802                 : 
    2803                 : template<class Handler>
    2804                 : void
    2805         4153166 : basic_parser<Handler>::
    2806                 : reset() noexcept
    2807                 : {
    2808         4153166 :     ec_ = {};
    2809         4153166 :     st_.clear();
    2810         4153166 :     more_ = true;
    2811         4153166 :     done_ = false;
    2812         4153166 :     clean_ = true;
    2813         4153166 :     num_buf_.clear();
    2814         4153166 : }
    2815                 : 
    2816                 : template<class Handler>
    2817                 : void
    2818              18 : basic_parser<Handler>::
    2819                 : fail(system::error_code ec) noexcept
    2820                 : {
    2821              18 :     if(! ec)
    2822                 :     {
    2823                 :         // assign an arbitrary
    2824                 :         // error code to prevent UB
    2825               1 :         BOOST_JSON_FAIL(ec_, error::incomplete);
    2826                 :     }
    2827                 :     else
    2828                 :     {
    2829              17 :         ec_ = ec;
    2830                 :     }
    2831              18 :     done_ = false;
    2832              18 : }
    2833                 : 
    2834                 : //----------------------------------------------------------
    2835                 : 
    2836                 : template<class Handler>
    2837                 : std::size_t
    2838        10726454 : basic_parser<Handler>::
    2839                 : write_some(
    2840                 :     bool more,
    2841                 :     char const* data,
    2842                 :     std::size_t size,
    2843                 :     system::error_code& ec)
    2844                 : {
    2845                 :     // see if we exited via exception
    2846                 :     // on the last call to write_some
    2847        10726454 :     if(! clean_)
    2848                 :     {
    2849                 :         // prevent UB
    2850               1 :         if(! ec_)
    2851                 :         {
    2852               1 :             BOOST_JSON_FAIL(ec_, error::exception);
    2853                 :         }
    2854                 :     }
    2855        10726454 :     if(ec_)
    2856                 :     {
    2857                 :         // error is sticky
    2858               5 :         ec = ec_;
    2859               5 :         return 0;
    2860                 :     }
    2861        10726449 :     clean_ = false;
    2862        10726449 :     more_ = more;
    2863        10726449 :     end_ = data + size;
    2864                 :     const char* p;
    2865        10726449 :     if(BOOST_JSON_LIKELY(st_.empty()))
    2866                 :     {
    2867                 :         // first time
    2868         2164976 :         depth_ = opt_.max_depth;
    2869         2164976 :         if(BOOST_JSON_UNLIKELY(
    2870                 :             ! h_.on_document_begin(ec_)))
    2871                 :         {
    2872            7928 :             ec = ec_;
    2873            7928 :             return 0;
    2874                 :         }
    2875         2149119 :         p = parse_document(data, std::true_type());
    2876                 :     }
    2877                 :     else
    2878                 :     {
    2879         8561473 :         p = parse_document(data, std::false_type());
    2880                 :     }
    2881                 : 
    2882        10691424 :     if(BOOST_JSON_LIKELY(p != sentinel()))
    2883                 :     {
    2884         2099195 :         BOOST_ASSERT(! ec_);
    2885         2099195 :         if(! done_)
    2886                 :         {
    2887         2031780 :             done_ = true;
    2888         2031780 :             h_.on_document_end(ec_);
    2889                 :         }
    2890                 :     }
    2891                 :     else
    2892                 :     {
    2893         8592229 :         if(! ec_)
    2894                 :         {
    2895         8565374 :             if(! more_)
    2896                 :             {
    2897             589 :                 BOOST_JSON_FAIL(ec_, error::incomplete);
    2898                 :             }
    2899         8564785 :             else if(! st_.empty())
    2900                 :             {
    2901                 :                 // consume as much trailing whitespace in
    2902                 :                 // the JSON document as possible, but still
    2903                 :                 // consider the parse complete
    2904                 :                 state st;
    2905         8564785 :                 st_.peek(st);
    2906         8564785 :                 if( st == state::doc3 &&
    2907           88551 :                     ! done_)
    2908                 :                 {
    2909           70724 :                     done_ = true;
    2910           70724 :                     h_.on_document_end(ec_);
    2911                 :                 }
    2912                 :             }
    2913                 :         }
    2914         8590585 :         p = end_;
    2915                 :     }
    2916        10685788 :     ec = ec_;
    2917        10685788 :     clean_ = true;
    2918        10685788 :     return p - data;
    2919                 : }
    2920                 : 
    2921                 : template<class Handler>
    2922                 : std::size_t
    2923               1 : basic_parser<Handler>::
    2924                 : write_some(
    2925                 :     bool more,
    2926                 :     char const* data,
    2927                 :     std::size_t size,
    2928                 :     std::error_code& ec)
    2929                 : {
    2930               1 :     system::error_code jec;
    2931               1 :     std::size_t const result = write_some(more, data, size, jec);
    2932               1 :     ec = jec;
    2933               1 :     return result;
    2934                 : }
    2935                 : 
    2936                 : #endif
    2937                 : 
    2938                 : } // namespace json
    2939                 : } // namespace boost
    2940                 : 
    2941                 : #ifdef _MSC_VER
    2942                 : #pragma warning(pop)
    2943                 : #endif
    2944                 : 
    2945                 : #endif
        

Generated by: LCOV version 2.3