Optimize ParseNumber()
This commit is contained in:
parent
881c91d696
commit
a71f2e60ff
@ -730,8 +730,8 @@ private:
|
|||||||
NumberStream(GenericReader& reader, InputStream& is) : is(is) { (void)reader; }
|
NumberStream(GenericReader& reader, InputStream& is) : is(is) { (void)reader; }
|
||||||
~NumberStream() {}
|
~NumberStream() {}
|
||||||
|
|
||||||
Ch Peek() { return is.Peek(); }
|
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
|
||||||
Ch Take() { return is.Take(); }
|
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
|
||||||
size_t Tell() { return is.Tell(); }
|
size_t Tell() { return is.Tell(); }
|
||||||
const char* Pop() { return 0; }
|
const char* Pop() { return 0; }
|
||||||
|
|
||||||
@ -748,7 +748,7 @@ private:
|
|||||||
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
|
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
|
||||||
~NumberStream() {}
|
~NumberStream() {}
|
||||||
|
|
||||||
Ch Take() {
|
RAPIDJSON_FORCEINLINE Ch Take() {
|
||||||
stackStream.Put((char)Base::is.Peek());
|
stackStream.Put((char)Base::is.Peek());
|
||||||
return Base::is.Take();
|
return Base::is.Take();
|
||||||
}
|
}
|
||||||
@ -869,28 +869,45 @@ private:
|
|||||||
s.Take();
|
s.Take();
|
||||||
|
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
d = use64bit ? i64 : i;
|
#if RAPIDJSON_64BIT
|
||||||
useDouble = true;
|
// Use i64 to store significand in 64-bit architecture
|
||||||
|
if (!use64bit)
|
||||||
|
i64 = i;
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (d >= 9007199254740991.0) {
|
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) { // 2^53 - 1 for fast path
|
||||||
if (parseFlags & kParseFullPrecisionFlag)
|
if (parseFlags & kParseFullPrecisionFlag) {
|
||||||
|
while (s.Peek() >= '0' && s.Peek() <= '9')
|
||||||
|
s.Take();
|
||||||
useStrtod = true;
|
useStrtod = true;
|
||||||
|
--expFrac;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d = d * 10.0 + static_cast<unsigned>(s.Take() - '0');
|
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||||
--expFrac;
|
--expFrac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!useStrtod)
|
||||||
|
d = (double)i64;
|
||||||
|
#else
|
||||||
|
// Use double to store significand in 32-bit architecture
|
||||||
|
d = use64bit ? (double)i64 : (double)i;
|
||||||
|
#endif
|
||||||
|
useDouble = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
if ((parseFlags & kParseFullPrecisionFlag) == 0 || !useStrtod) {
|
||||||
//s.Take();
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (parseFlags & kParseFullPrecisionFlag)
|
d = d * 10.0 + (s.Take() - '0');
|
||||||
|
--expFrac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (s.Peek() >= '0' && s.Peek() <= '9')
|
||||||
s.Take();
|
s.Take();
|
||||||
else
|
|
||||||
d = d * 10 + (s.Take() - '0');
|
|
||||||
--expFrac;
|
--expFrac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,15 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
|
||||||
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
|
StringStream s(json_);
|
||||||
|
BaseReaderHandler<> h;
|
||||||
|
Reader reader;
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseFullPrecisionFlag>(s, h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterative_DummyHandler)) {
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterative_DummyHandler)) {
|
||||||
for (size_t i = 0; i < kTrialCount; i++) {
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
StringStream s(json_);
|
StringStream s(json_);
|
||||||
|
@ -184,7 +184,7 @@ static void TestParseDouble() {
|
|||||||
StringStream s(str); \
|
StringStream s(str); \
|
||||||
ParseDoubleHandler h; \
|
ParseDoubleHandler h; \
|
||||||
Reader reader; \
|
Reader reader; \
|
||||||
reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h); \
|
ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); \
|
||||||
EXPECT_EQ(1u, h.step_); \
|
EXPECT_EQ(1u, h.step_); \
|
||||||
if (fullPrecision) { \
|
if (fullPrecision) { \
|
||||||
EXPECT_EQ(x, h.actual_); \
|
EXPECT_EQ(x, h.actual_); \
|
||||||
@ -195,67 +195,65 @@ static void TestParseDouble() {
|
|||||||
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
|
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
|
||||||
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
|
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
|
||||||
TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
|
TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
|
||||||
TEST_DOUBLE(fullPrecision, "1.5", 1.5);
|
TEST_DOUBLE(fullPrecision, "1.5", 1.5);
|
||||||
TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
|
TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
|
||||||
TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
|
TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
|
||||||
TEST_DOUBLE(fullPrecision, "1E10", 1E10);
|
TEST_DOUBLE(fullPrecision, "1E10", 1E10);
|
||||||
TEST_DOUBLE(fullPrecision, "1e10", 1e10);
|
TEST_DOUBLE(fullPrecision, "1e10", 1e10);
|
||||||
TEST_DOUBLE(fullPrecision, "1E+10", 1E+10);
|
TEST_DOUBLE(fullPrecision, "1E+10", 1E+10);
|
||||||
TEST_DOUBLE(fullPrecision, "1E-10", 1E-10);
|
TEST_DOUBLE(fullPrecision, "1E-10", 1E-10);
|
||||||
TEST_DOUBLE(fullPrecision, "-1E10", -1E10);
|
TEST_DOUBLE(fullPrecision, "-1E10", -1E10);
|
||||||
TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
|
TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
|
||||||
TEST_DOUBLE(fullPrecision, "-1E+10", -1E+10);
|
TEST_DOUBLE(fullPrecision, "-1E+10", -1E+10);
|
||||||
TEST_DOUBLE(fullPrecision, "-1E-10", -1E-10);
|
TEST_DOUBLE(fullPrecision, "-1E-10", -1E-10);
|
||||||
TEST_DOUBLE(fullPrecision, "1.234E+10", 1.234E+10);
|
TEST_DOUBLE(fullPrecision, "1.234E+10", 1.234E+10);
|
||||||
TEST_DOUBLE(fullPrecision, "1.234E-10", 1.234E-10);
|
TEST_DOUBLE(fullPrecision, "1.234E-10", 1.234E-10);
|
||||||
TEST_DOUBLE(fullPrecision, "1.79769e+308", 1.79769e+308);
|
TEST_DOUBLE(fullPrecision, "1.79769e+308", 1.79769e+308);
|
||||||
TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
|
TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
|
||||||
TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
|
TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
|
||||||
TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
|
TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
|
||||||
TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
|
TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
|
||||||
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
|
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
|
||||||
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
||||||
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
||||||
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
||||||
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
|
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
|
||||||
|
TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
|
||||||
|
|
||||||
{
|
{
|
||||||
char n1e308[310]; // '1' followed by 308 '0'
|
char n1e308[310]; // '1' followed by 308 '0'
|
||||||
n1e308[0] = '1';
|
n1e308[0] = '1';
|
||||||
for (int i = 1; i < 309; i++)
|
for (int i = 1; i < 309; i++)
|
||||||
n1e308[i] = '0';
|
n1e308[i] = '0';
|
||||||
n1e308[309] = '\0';
|
n1e308[309] = '\0';
|
||||||
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
TEST_DOUBLE(fullPrecision, n1e308, 1E308);
|
||||||
}
|
|
||||||
|
|
||||||
// Random test for double
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint64_t u;
|
|
||||||
}u;
|
|
||||||
Random r;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < 100000; i++) {
|
|
||||||
do {
|
|
||||||
// Need to call r() in two statements for cross-platform coherent sequence.
|
|
||||||
u.u = uint64_t(r()) << 32;
|
|
||||||
u.u |= uint64_t(r());
|
|
||||||
} while (std::isnan(u.d) || std::isinf(u.d)
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// VC's strtod() has problem with denormal numbers
|
|
||||||
|| !std::isnormal(u.d)
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
char buffer[32];
|
|
||||||
*internal::dtoa(u.d, buffer) = '\0';
|
|
||||||
TEST_DOUBLE(fullPrecision, buffer, u.d);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#if 1
|
||||||
|
// Random test for double
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u;
|
||||||
|
}u;
|
||||||
|
Random r;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 100000; i++) {
|
||||||
|
do {
|
||||||
|
// Need to call r() in two statements for cross-platform coherent sequence.
|
||||||
|
u.u = uint64_t(r()) << 32;
|
||||||
|
u.u |= uint64_t(r());
|
||||||
|
} while (std::isnan(u.d) || std::isinf(u.d) || !std::isnormal(u.d));
|
||||||
|
|
||||||
|
char buffer[32];
|
||||||
|
*internal::dtoa(u.d, buffer) = '\0';
|
||||||
|
TEST_DOUBLE(fullPrecision, buffer, u.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef TEST_DOUBLE
|
#undef TEST_DOUBLE
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user