From bf756d592ab46c10d35cb077a3d87eef5857019d Mon Sep 17 00:00:00 2001 From: Dmitry Arkhipov Date: Wed, 31 May 2023 23:23:01 +0300 Subject: [PATCH] split parse_number into separate instatntiations per number parsing mode --- include/boost/json/basic_parser.hpp | 8 +- include/boost/json/basic_parser_impl.hpp | 114 +++++++++++++++++------ 2 files changed, 90 insertions(+), 32 deletions(-) diff --git a/include/boost/json/basic_parser.hpp b/include/boost/json/basic_parser.hpp index 0d328ebff..09cbce606 100644 --- a/include/boost/json/basic_parser.hpp +++ b/include/boost/json/basic_parser.hpp @@ -292,6 +292,9 @@ class basic_parser bool neg; }; + template< char C > + struct parse_number_helper; + // optimization: must come first Handler h_; @@ -440,10 +443,11 @@ class basic_parser std::integral_constant is_key, /*std::integral_constant*/ bool allow_bad_utf8); - template + template const char* parse_number(const char* p, std::integral_constant stack_empty, - std::integral_constant first); + std::integral_constant first, + std::integral_constant mode); template diff --git a/include/boost/json/basic_parser_impl.hpp b/include/boost/json/basic_parser_impl.hpp index b30d46b32..4c7493b47 100644 --- a/include/boost/json/basic_parser_impl.hpp +++ b/include/boost/json/basic_parser_impl.hpp @@ -199,6 +199,30 @@ enum json_literal //---------------------------------------------------------- +template< class Handler > +template< char C > +struct basic_parser:: +parse_number_helper +{ + basic_parser* parser; + char const* p; + + template< std::size_t N > + char const* + operator()( mp11::mp_size_t ) const + { + return parser->parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant< + number_parse_mode_t, + static_cast(N)>() ); + } +}; + +//---------------------------------------------------------- + template void basic_parser:: @@ -616,13 +640,19 @@ parse_value(const char* p, switch(*p) { case '0': - return parse_number(p, std::true_type(), std::integral_constant()); + return mp11::mp_with_index<3>( + static_cast(opt_.number_parse_mode), + parse_number_helper<'0'>{ this, p }); case '-': - return parse_number(p, std::true_type(), std::integral_constant()); + return mp11::mp_with_index<3>( + static_cast(opt_.number_parse_mode), + parse_number_helper<'-'>{ this, p }); case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - return parse_number(p, std::true_type(), std::integral_constant()); + return mp11::mp_with_index<3>( + static_cast(opt_.number_parse_mode), + parse_number_helper<'+'>{ this, p }); case 'n': return parse_literal( p, mp11::mp_int() ); case 't': @@ -735,7 +765,29 @@ resume_value(const char* p, case state::num7: case state::num8: case state::exp1: case state::exp2: case state::exp3: - return parse_number(p, std::false_type(), std::integral_constant()); + switch( opt_.number_parse_mode ) + { + case number_parse_mode_t::imprecise: + return parse_number( + p, + std::false_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::precise: + return parse_number( + p, + std::false_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::none: + return parse_number( + p, + std::false_type(), + std::integral_constant(), + std::integral_constant()); + default: + BOOST_JSON_UNREACHABLE(); + } // KRYSTIAN NOTE: these are special cases case state::val1: @@ -1970,13 +2022,17 @@ parse_array(const char* p, //---------------------------------------------------------- template -template +template const char* basic_parser:: parse_number(const char* p, std::integral_constant stack_empty, - std::integral_constant first) + std::integral_constant first, + std::integral_constant mode) { + constexpr bool precise_parsing = mode == number_parse_mode_t::precise; + constexpr bool no_parsing = mode == number_parse_mode_t::none; + // only one of these will be true if we are not resuming // if negative then !zero_first && !nonzero_first // if zero_first then !nonzero_first && !negative @@ -1984,10 +2040,6 @@ parse_number(const char* p, bool const negative = first == '-'; bool const zero_first = first == '0'; bool const nonzero_first = first == '+'; - bool const precise_parsing = - opt_.number_parse_mode == number_parse_mode_t::precise; - bool const no_parsing = - opt_.number_parse_mode == number_parse_mode_t::none; detail::const_stream_wrapper cs(p, end_); number num; const char* begin = cs.begin(); @@ -2037,8 +2089,10 @@ parse_number(const char* p, return fail(cs.begin(), error::syntax, &loc); } - if( !no_parsing ) + BOOST_IF_CONSTEXPR( !no_parsing ) num.mant = detail::parse_unsigned( 0, cs.begin(), n1 ); + else + num.mant = 0; cs += n1; @@ -2066,7 +2120,7 @@ parse_number(const char* p, ++cs; goto do_exp1; } - if( negative && !no_parsing ) + BOOST_IF_CONSTEXPR( negative && !no_parsing ) num.mant = ~num.mant + 1; goto finish_signed; } @@ -2093,7 +2147,7 @@ parse_number(const char* p, goto do_num7; } - if( !no_parsing ) + BOOST_IF_CONSTEXPR( !no_parsing ) num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 ); BOOST_ASSERT(num.bias == 0); @@ -2190,7 +2244,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return maybe_suspend( cs.begin(), state::num1, num); @@ -2215,7 +2269,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num2, num); } @@ -2230,7 +2284,7 @@ parse_number(const char* p, if( num.mant > 922337203685477580 || ( num.mant == 922337203685477580 && c > '8')) break; - else if( !no_parsing ) + BOOST_IF_CONSTEXPR( !no_parsing ) num.mant = 10 * num.mant + ( c - '0' ); continue; } @@ -2250,7 +2304,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num2, num); } @@ -2265,7 +2319,7 @@ parse_number(const char* p, if( num.mant > 1844674407370955161 || ( num.mant == 1844674407370955161 && c > '5')) break; - else if( !no_parsing ) + BOOST_IF_CONSTEXPR( !no_parsing ) num.mant = 10 * num.mant + ( c - '0' ); } else @@ -2293,7 +2347,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num3, num); } @@ -2339,7 +2393,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return maybe_suspend( cs.begin(), state::num4, num); @@ -2378,7 +2432,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num5, num); } @@ -2416,7 +2470,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num6, num); } @@ -2456,7 +2510,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num7, num); } @@ -2494,7 +2548,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::num8, num); } @@ -2539,7 +2593,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return maybe_suspend( cs.begin(), state::exp1, num); @@ -2570,7 +2624,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::exp2, num); } @@ -2609,7 +2663,7 @@ parse_number(const char* p, {begin, cs.used(begin)}, ec_))) return fail(cs.begin()); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) num_buf_.append( begin, cs.used(begin) ); return suspend(cs.begin(), state::exp3, num); } @@ -2630,7 +2684,7 @@ parse_number(const char* p, return fail(cs.begin(), error::exponent_overflow, &loc); } ++cs; - if( !no_parsing ) + BOOST_IF_CONSTEXPR( !no_parsing ) num.exp = 10 * num.exp + ( c - '0' ); continue; } @@ -2683,7 +2737,7 @@ parse_number(const char* p, double d; std::size_t const size = cs.used(begin); BOOST_ASSERT( !num_buf_.size() || precise_parsing ); - if( precise_parsing ) + BOOST_IF_CONSTEXPR( precise_parsing ) { char const* data = begin; std::size_t full_size = size; @@ -2701,7 +2755,7 @@ parse_number(const char* p, BOOST_ASSERT( err.ptr == data + full_size ); (void)err; } - else if ( no_parsing ) + else BOOST_IF_CONSTEXPR( no_parsing ) d = 0; else d = detail::dec_to_float(