Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormiloyip <miloyip@gmail.com>2014-09-05 15:51:20 +0400
committermiloyip <miloyip@gmail.com>2014-09-05 15:51:20 +0400
commita71f2e60ff8507b08ebd180dfe8484cc47b4ecd4 (patch)
tree7ada21332a10a6953f2bebd98b937f9f91fc5214
parent881c91d696f06b7f302af6d04ec14dd08db66ceb (diff)
Optimize ParseNumber()
-rw-r--r--include/rapidjson/reader.h45
-rw-r--r--test/perftest/rapidjsontest.cpp9
-rw-r--r--test/unittest/readertest.cpp116
3 files changed, 97 insertions, 73 deletions
diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
index 4aa98b18..0816b1f1 100644
--- a/include/rapidjson/reader.h
+++ b/include/rapidjson/reader.h
@@ -730,8 +730,8 @@ private:
NumberStream(GenericReader& reader, InputStream& is) : is(is) { (void)reader; }
~NumberStream() {}
- Ch Peek() { return is.Peek(); }
- Ch Take() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+ RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
size_t Tell() { return is.Tell(); }
const char* Pop() { return 0; }
@@ -748,7 +748,7 @@ private:
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
~NumberStream() {}
- Ch Take() {
+ RAPIDJSON_FORCEINLINE Ch Take() {
stackStream.Put((char)Base::is.Peek());
return Base::is.Take();
}
@@ -869,28 +869,45 @@ private:
s.Take();
if (!useDouble) {
- d = use64bit ? i64 : i;
- useDouble = true;
-
+#if RAPIDJSON_64BIT
+ // Use i64 to store significand in 64-bit architecture
+ if (!use64bit)
+ i64 = i;
+
while (s.Peek() >= '0' && s.Peek() <= '9') {
- if (d >= 9007199254740991.0) {
- if (parseFlags & kParseFullPrecisionFlag)
+ if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) { // 2^53 - 1 for fast path
+ if (parseFlags & kParseFullPrecisionFlag) {
+ while (s.Peek() >= '0' && s.Peek() <= '9')
+ s.Take();
useStrtod = true;
+ --expFrac;
+ }
break;
}
else {
- d = d * 10.0 + static_cast<unsigned>(s.Take() - '0');
+ i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
--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') {
- //s.Take();
- if (parseFlags & kParseFullPrecisionFlag)
+ if ((parseFlags & kParseFullPrecisionFlag) == 0 || !useStrtod) {
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ d = d * 10.0 + (s.Take() - '0');
+ --expFrac;
+ }
+ }
+ else {
+ while (s.Peek() >= '0' && s.Peek() <= '9')
s.Take();
- else
- d = d * 10 + (s.Take() - '0');
--expFrac;
}
diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp
index 6a451131..2321947c 100644
--- a/test/perftest/rapidjsontest.cpp
+++ b/test/perftest/rapidjsontest.cpp
@@ -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)) {
for (size_t i = 0; i < kTrialCount; i++) {
StringStream s(json_);
diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp
index a82aacfa..bbd33d97 100644
--- a/test/unittest/readertest.cpp
+++ b/test/unittest/readertest.cpp
@@ -184,7 +184,7 @@ static void TestParseDouble() {
StringStream s(str); \
ParseDoubleHandler h; \
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_); \
if (fullPrecision) { \
EXPECT_EQ(x, h.actual_); \
@@ -195,67 +195,65 @@ static void TestParseDouble() {
EXPECT_DOUBLE_EQ(x, h.actual_); \
}
-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.5", 1.5);
-TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
-TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
-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, "-1E10", -1E10);
-TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
-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.79769e+308", 1.79769e+308);
-TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
-TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
-TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
-TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
-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, "-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, "123e34", 123e34); // Fast Path Cases In Disguise
-
-{
- char n1e308[310]; // '1' followed by 308 '0'
- n1e308[0] = '1';
- for (int i = 1; i < 309; i++)
- n1e308[i] = '0';
- n1e308[309] = '\0';
- TEST_DOUBLE(fullPrecision, n1e308, 1E308);
-}
+ 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.5", 1.5);
+ TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
+ TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
+ 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, "-1E10", -1E10);
+ TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
+ 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.79769e+308", 1.79769e+308);
+ TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
+ TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
+ TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
+ TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
+ 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, "-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, "123e34", 123e34); // Fast Path Cases In Disguise
+ TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
-// 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 n1e308[310]; // '1' followed by 308 '0'
+ n1e308[0] = '1';
+ for (int i = 1; i < 309; i++)
+ n1e308[i] = '0';
+ n1e308[309] = '\0';
+ TEST_DOUBLE(fullPrecision, n1e308, 1E308);
+ }
- 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
}