Commit 62a9a6b0 authored by Milo Yip's avatar Milo Yip

Merge pull request #589 from jnicholls/rawnumber

RawNumber Improvements / Clang Test Fix / Whitespace Cleanup
parents 4fdcb10c 926d7ffc
...@@ -1063,11 +1063,11 @@ private: ...@@ -1063,11 +1063,11 @@ private:
} }
#endif #endif
template<typename InputStream, bool backup> template<typename InputStream, bool backup, bool pushOnTake>
class NumberStream; class NumberStream;
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, false> { class NumberStream<InputStream, false, false> {
public: public:
typedef typename InputStream::Ch Ch; typedef typename InputStream::Ch Ch;
...@@ -1090,10 +1090,10 @@ private: ...@@ -1090,10 +1090,10 @@ private:
}; };
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> { class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
typedef NumberStream<InputStream, false> Base; typedef NumberStream<InputStream, false, false> Base;
public: public:
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {} NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
~NumberStream() {} ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch TakePush() { RAPIDJSON_FORCEINLINE Ch TakePush() {
...@@ -1116,13 +1116,25 @@ private: ...@@ -1116,13 +1116,25 @@ private:
StackStream<char> stackStream; StackStream<char> stackStream;
}; };
template<typename InputStream>
class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
typedef NumberStream<InputStream, true, false> Base;
public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
};
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) { void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
NumberStream<InputStream, NumberStream<InputStream,
((parseFlags & kParseNumbersAsStringsFlag) != 0) ? ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
((parseFlags & kParseInsituFlag) == 0) : ((parseFlags & kParseInsituFlag) == 0) :
((parseFlags & kParseFullPrecisionFlag) != 0)> s(*this, copy.s); ((parseFlags & kParseFullPrecisionFlag) != 0),
(parseFlags & kParseNumbersAsStringsFlag) != 0 &&
(parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
size_t startOffset = s.Tell(); size_t startOffset = s.Tell();
...@@ -1210,9 +1222,6 @@ private: ...@@ -1210,9 +1222,6 @@ private:
int expFrac = 0; int expFrac = 0;
size_t decimalPosition; size_t decimalPosition;
if (Consume(s, '.')) { if (Consume(s, '.')) {
if (((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0)) {
s.Push('.');
}
decimalPosition = s.Length(); decimalPosition = s.Length();
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
...@@ -1260,10 +1269,6 @@ private: ...@@ -1260,10 +1269,6 @@ private:
// Parse exp = e [ minus / plus ] 1*DIGIT // Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0; int exp = 0;
if (Consume(s, 'e') || Consume(s, 'E')) { if (Consume(s, 'e') || Consume(s, 'E')) {
if ( ((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0) ) {
s.Push( 'e' );
}
if (!useDouble) { if (!useDouble) {
d = static_cast<double>(use64bit ? i64 : i); d = static_cast<double>(use64bit ? i64 : i);
useDouble = true; useDouble = true;
...@@ -1316,14 +1321,15 @@ private: ...@@ -1316,14 +1321,15 @@ private:
cont = handler.RawNumber(str, SizeType(length), false); cont = handler.RawNumber(str, SizeType(length), false);
} }
else { else {
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
SizeType numCharsToCopy = static_cast<SizeType>(s.Length()); SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
StringStream srcStream(s.Pop());
StackStream<typename TargetEncoding::Ch> dstStream(stack_);
while (numCharsToCopy--) { while (numCharsToCopy--) {
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, stackStream); Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
} }
stackStream.Put('\0'); dstStream.Put('\0');
const typename TargetEncoding::Ch* str = stackStream.Pop(); const typename TargetEncoding::Ch* str = dstStream.Pop();
const SizeType length = static_cast<SizeType>(stackStream.Length()) - 1; const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
cont = handler.RawNumber(str, SizeType(length), true); cont = handler.RawNumber(str, SizeType(length), true);
} }
} }
......
...@@ -38,6 +38,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") ...@@ -38,6 +38,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
# If the user is running a newer version of Clang that includes the
# -Wdouble-promotion, we will ignore that warning.
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-double-promotion")
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
endif() endif()
......
...@@ -241,13 +241,13 @@ static void TestParseDouble() { ...@@ -241,13 +241,13 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form
// Since // Since
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... 10^-324 // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... �� 10^-324
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... 10 ^ -324 // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... �� 10 ^ -324
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308 // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
// More closer to normal/subnormal boundary // More closer to normal/subnormal boundary
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... 10^-308 // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... �� 10^-308
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308); TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308);
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308); TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308);
...@@ -1541,7 +1541,8 @@ struct NumbersAsStringsHandler { ...@@ -1541,7 +1541,8 @@ struct NumbersAsStringsHandler {
// 'str' is not null-terminated // 'str' is not null-terminated
bool RawNumber(const char* str, SizeType length, bool) { bool RawNumber(const char* str, SizeType length, bool) {
EXPECT_TRUE(str != 0); EXPECT_TRUE(str != 0);
EXPECT_TRUE(strncmp(str, "3.1416", length) == 0); EXPECT_TRUE(expected_len_ == length);
EXPECT_TRUE(strncmp(str, expected_, length) == 0);
return true; return true;
} }
bool String(const char*, SizeType, bool) { return true; } bool String(const char*, SizeType, bool) { return true; }
...@@ -1550,24 +1551,84 @@ struct NumbersAsStringsHandler { ...@@ -1550,24 +1551,84 @@ struct NumbersAsStringsHandler {
bool EndObject(SizeType) { return true; } bool EndObject(SizeType) { return true; }
bool StartArray() { return true; } bool StartArray() { return true; }
bool EndArray(SizeType) { return true; } bool EndArray(SizeType) { return true; }
NumbersAsStringsHandler(const char* expected)
: expected_(expected)
, expected_len_(strlen(expected)) {}
const char* expected_;
size_t expected_len_;
}; };
TEST(Reader, NumbersAsStrings) { TEST(Reader, NumbersAsStrings) {
{ {
const char* json = "{ \"pi\": 3.1416 } "; const char* json = "{ \"pi\": 3.1416 } ";
StringStream s(json); StringStream s(json);
NumbersAsStringsHandler h; NumbersAsStringsHandler h("3.1416");
Reader reader; Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
char* json = StrDup("{ \"pi\": 3.1416 } "); char* json = StrDup("{ \"pi\": 3.1416 } ");
InsituStringStream s(json); InsituStringStream s(json);
NumbersAsStringsHandler h; NumbersAsStringsHandler h("3.1416");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
free(json);
}
{
const char* json = "{ \"gigabyte\": 1.0e9 } ";
StringStream s(json);
NumbersAsStringsHandler h("1.0e9");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"gigabyte\": 1.0e9 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("1.0e9");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
free(json);
}
{
const char* json = "{ \"pi\": 314.159e-2 } ";
StringStream s(json);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"gigabyte\": 314.159e-2 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
free(json);
}
{
const char* json = "{ \"negative\": -1.54321 } ";
StringStream s(json);
NumbersAsStringsHandler h("-1.54321");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"negative\": -1.54321 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("-1.54321");
Reader reader; Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
free(json); free(json);
} }
{
const char* json = "{ \"pi\": 314.159e-2 } ";
std::stringstream ss(json);
IStreamWrapper s(ss);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
} }
template <unsigned extraFlags> template <unsigned extraFlags>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment