2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-19 04:12:14 +00:00

mode to not parse numbers

This commit is contained in:
Dmitry Arkhipov
2023-05-31 18:12:44 +03:00
committed by Dmitry Arkhipov
parent 105e74e46f
commit 285c3aa5a2
7 changed files with 84 additions and 23 deletions

View File

@@ -668,12 +668,6 @@ static bool parse_option( char const * s )
char opt = *s++;
if( opt == 'p' )
{
popts.precise_parsing = true;
return *s == 0;
}
if( *s++ != ':' )
{
return false;
@@ -711,6 +705,22 @@ static bool parse_option( char const * s )
case 'b':
s_branch = s;
break;
case 'm':
switch( *s )
{
case 'i':
popts.numbers = number_precision::imprecise;
break;
case 'p':
popts.numbers = number_precision::precise;
break;
case 'n':
popts.numbers = number_precision::none;
break;
default:
return false;
}
break;
}
return true;
@@ -817,7 +827,11 @@ main(
" (default all)\n"
" -n:<number> Number of trials (default 6)\n"
" -b:<branch> Branch label for boost implementations\n"
" -p Enable precise parsing\n"
" -m:(i|p|n) Number parsing mode\n"
" (i: imprecise)\n"
" (p: precise)\n"
" (n: none)\n"
" (default imprecise)\n"
;
return 4;

View File

@@ -24,6 +24,8 @@
<member><link linkend="json.ref.boost__json__basic_parser">basic_parser</link></member>
<member><link linkend="json.ref.boost__json__key_value_pair">key_value_pair</link></member>
<member><link linkend="json.ref.boost__json__monotonic_resource">monotonic_resource</link></member>
<member><link linkend="json.ref.boost__json__monotonic_resource">monotonic_resource</link></member>
<member><link linkend="json.ref.boost__json__number_precision">number_precision</link></member>
<member><link linkend="json.ref.boost__json__object">object</link></member>
<member><link linkend="json.ref.boost__json__parser">parser</link></member>
<member><link linkend="json.ref.boost__json__parse_options">parse_options</link></member>

View File

@@ -1977,6 +1977,9 @@ parse_number(const char* p,
std::integral_constant<bool, StackEmpty_> stack_empty,
std::integral_constant<char, First_> first)
{
bool const precise_parsing = opt_.numbers == number_precision::precise;
bool const no_parsing = opt_.numbers == number_precision::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,7 +1987,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_.precise_parsing;
detail::const_stream_wrapper cs(p, end_);
number num;
const char* begin = cs.begin();
@@ -2034,7 +2036,10 @@ parse_number(const char* p,
return fail(cs.begin(), error::syntax, &loc);
}
num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
if( !no_parsing )
num.mant = detail::parse_unsigned( 0, cs.begin(), n1 );
else
num.mant = 0;
cs += n1;
@@ -2062,7 +2067,7 @@ parse_number(const char* p,
++cs;
goto do_exp1;
}
if(negative)
if( negative && !no_parsing )
num.mant = ~num.mant + 1;
goto finish_signed;
}
@@ -2089,7 +2094,8 @@ parse_number(const char* p,
goto do_num7;
}
num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
if( !no_parsing )
num.mant = detail::parse_unsigned( num.mant, cs.begin(), n2 );
BOOST_ASSERT(num.bias == 0);
@@ -2225,7 +2231,8 @@ do_num2:
if( num.mant > 922337203685477580 || (
num.mant == 922337203685477580 && c > '8'))
break;
num.mant = 10 * num.mant + ( c - '0' );
else if( !no_parsing )
num.mant = 10 * num.mant + ( c - '0' );
continue;
}
goto do_num6; // [.eE]
@@ -2259,7 +2266,8 @@ do_num2:
if( num.mant > 1844674407370955161 || (
num.mant == 1844674407370955161 && c > '5'))
break;
num.mant = 10 * num.mant + ( c - '0' );
else if( !no_parsing )
num.mant = 10 * num.mant + ( c - '0' );
}
else
{
@@ -2498,7 +2506,7 @@ do_num8:
c >= '0' && c <= '9'))
{
++cs;
if(BOOST_JSON_LIKELY(
if(!no_parsing && BOOST_JSON_LIKELY(
num.mant <= 9007199254740991)) // 2^53-1
{
--num.bias;
@@ -2623,7 +2631,8 @@ do_exp3:
return fail(cs.begin(), error::exponent_overflow, &loc);
}
++cs;
num.exp = 10 * num.exp + ( c - '0' );
if( !no_parsing )
num.exp = 10 * num.exp + ( c - '0' );
continue;
}
}
@@ -2693,6 +2702,8 @@ finish_dub:
BOOST_ASSERT( err.ptr == data + full_size );
(void)err;
}
else if ( no_parsing )
d = 0;
else
d = detail::dec_to_float(
num.mant,

View File

@@ -16,6 +16,28 @@
namespace boost {
namespace json {
/** Enumeration of number parsing modes
These values are used to select the way to parse numbers.
@see
@ref parse_options,
@ref basic_parser,
@ref parser.
*/
enum class number_precision : unsigned char
{
/// Fast, but potentially less precise mode.
imprecise,
/// Slower, but precise mode.
precise,
/// The fastest mode, that only validates encountered numbers without
/// parsing them.
none,
};
/** Parser options
This structure is used for specifying
@@ -44,15 +66,20 @@ struct parse_options
*/
std::size_t max_depth = 32;
/** Number prasing mode
/** Number pasing mode
This selects enables precise parsing at the cost of performance.
This selects the way to parse numbers. The default is to parse them
fast, but with possible slight imprecision for floating point numbers
with larger mantissas. Users can also choose to parse numbers slower
but with full precision. Or to not parse them at all, and only validate
numbers. The latter mode is useful for @ref basic_parser instantiations
that wish to treat numbers in a custom way.
@see
@ref basic_parser,
@ref stream_parser.
*/
bool precise_parsing = false;
number_precision numbers = number_precision::imprecise;
/** Non-standard extension option

View File

@@ -279,7 +279,7 @@ testPrecise()
{
//[doc_parsing_precise
parse_options opt;
opt.precise_parsing = true;
opt.numbers = number_precision::precise;
value jv = parse( "1002.9111801605201", storage_ptr(), opt );
//]
(void)jv;

View File

@@ -228,7 +228,8 @@ public:
for (bool is_precise: {false, true})
{
parse_options po;
po.precise_parsing = is_precise;
po.numbers = is_precise ?
number_precision::precise : number_precision::imprecise;
double const got = f(s, po);
auto same = got == need;
auto close = same ?
@@ -241,6 +242,12 @@ public:
<< got << " != " << need << "\n";
}
}
// test that number_precision::none works
parse_options po;
po.numbers = number_precision::none;
double const got = f(s, po);
(void)got;
}
void
@@ -423,7 +430,7 @@ public:
sprintf( buffer, "%llu.%llue%d", x1, x2, x3 );
parse_options precise;
precise.precise_parsing = true;
precise.numbers = number_precision::precise;
checkAccuracy( buffer, 2 );
checkAccuracy( buffer, 0, precise );
}
@@ -441,7 +448,7 @@ public:
testExtraPrecision()
{
parse_options opts;
opts.precise_parsing = true;
opts.numbers = number_precision::precise;
BOOST_TEST(
parse("1002.9111801605201", {}, opts) == 1002.9111801605201 );
BOOST_TEST(

View File

@@ -358,7 +358,7 @@ public:
buffer.data()[1] = '.';
parse_options precise;
precise.precise_parsing = true;
precise.numbers = number_precision::precise;
stream_parser p( {}, precise );
error_code ec;