From abafb5b4c05a6808ec9d94794643c4f600c8cfe8 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 | 5 +- include/boost/json/basic_parser_impl.hpp | 150 ++++++++++++++++++----- 2 files changed, 123 insertions(+), 32 deletions(-) diff --git a/include/boost/json/basic_parser.hpp b/include/boost/json/basic_parser.hpp index 0d328ebff..f53f6e24a 100644 --- a/include/boost/json/basic_parser.hpp +++ b/include/boost/json/basic_parser.hpp @@ -440,10 +440,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 ae120f0a6..3a780fe87 100644 --- a/include/boost/json/basic_parser_impl.hpp +++ b/include/boost/json/basic_parser_impl.hpp @@ -605,13 +605,79 @@ parse_value(const char* p, switch(*p) { case '0': - return parse_number(p, std::true_type(), std::integral_constant()); + switch( opt_.number_parse_mode ) + { + case number_parse_mode_t::imprecise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::precise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::none: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + default: + BOOST_JSON_UNREACHABLE(); + } case '-': - return parse_number(p, std::true_type(), std::integral_constant()); + switch( opt_.number_parse_mode ) + { + case number_parse_mode_t::imprecise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::precise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::none: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + default: + BOOST_JSON_UNREACHABLE(); + } 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()); + switch( opt_.number_parse_mode ) + { + case number_parse_mode_t::imprecise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::precise: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + case number_parse_mode_t::none: + return parse_number( + p, + std::true_type(), + std::integral_constant(), + std::integral_constant()); + default: + BOOST_JSON_UNREACHABLE(); + } case 'n': return parse_literal( p, mp11::mp_int() ); case 't': @@ -708,7 +774,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: @@ -1874,13 +1962,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 @@ -1888,10 +1980,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(); @@ -1935,8 +2023,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; @@ -1964,7 +2054,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; } @@ -1991,7 +2081,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); @@ -2080,7 +2170,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); @@ -2105,7 +2195,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); } @@ -2120,7 +2210,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; } @@ -2140,7 +2230,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); } @@ -2155,7 +2245,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 @@ -2183,7 +2273,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); } @@ -2229,7 +2319,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); @@ -2268,7 +2358,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); } @@ -2306,7 +2396,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); } @@ -2346,7 +2436,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); } @@ -2384,7 +2474,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); } @@ -2429,7 +2519,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); @@ -2460,7 +2550,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); } @@ -2499,7 +2589,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); } @@ -2520,7 +2610,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; } @@ -2573,7 +2663,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; // if we previously suspended or if the current input ends with the @@ -2587,7 +2677,7 @@ parse_number(const char* p, } d = std::strtod( data, nullptr ); } - else if ( no_parsing ) + else BOOST_IF_CONSTEXPR( no_parsing ) d = 0; else d = detail::dec_to_float(