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
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_READER_H_ #ifndef RAPIDJSON_READER_H_
...@@ -127,7 +127,7 @@ RAPIDJSON_NAMESPACE_BEGIN ...@@ -127,7 +127,7 @@ RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// ParseFlag // ParseFlag
/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS /*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
\ingroup RAPIDJSON_CONFIG \ingroup RAPIDJSON_CONFIG
\brief User-defined kParseDefaultFlags definition. \brief User-defined kParseDefaultFlags definition.
...@@ -158,7 +158,7 @@ enum ParseFlag { ...@@ -158,7 +158,7 @@ enum ParseFlag {
/*! \class rapidjson::Handler /*! \class rapidjson::Handler
\brief Concept for receiving events from GenericReader upon parsing. \brief Concept for receiving events from GenericReader upon parsing.
The functions return true if no error occurs. If they return false, The functions return true if no error occurs. If they return false,
the event publisher should terminate the process. the event publisher should terminate the process.
\code \code
concept Handler { concept Handler {
...@@ -425,7 +425,7 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { ...@@ -425,7 +425,7 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
#ifdef RAPIDJSON_SIMD #ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream //! Template function specialization for InsituStringStream
template<> inline void SkipWhitespace(InsituStringStream& is) { template<> inline void SkipWhitespace(InsituStringStream& is) {
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_)); is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
} }
...@@ -443,17 +443,17 @@ template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& ...@@ -443,17 +443,17 @@ template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>&
// GenericReader // GenericReader
//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
/*! GenericReader parses JSON text from a stream, and send events synchronously to an /*! GenericReader parses JSON text from a stream, and send events synchronously to an
object implementing Handler concept. object implementing Handler concept.
It needs to allocate a stack for storing a single decoded string during It needs to allocate a stack for storing a single decoded string during
non-destructive parsing. non-destructive parsing.
For in-situ parsing, the decoded string is directly written to the source For in-situ parsing, the decoded string is directly written to the source
text string, no temporary buffer is required. text string, no temporary buffer is required.
A GenericReader object can be reused for parsing multiple JSON text. A GenericReader object can be reused for parsing multiple JSON text.
\tparam SourceEncoding Encoding of the input stream. \tparam SourceEncoding Encoding of the input stream.
\tparam TargetEncoding Encoding of the parse output. \tparam TargetEncoding Encoding of the parse output.
\tparam StackAllocator Allocator type for stack. \tparam StackAllocator Allocator type for stack.
...@@ -525,7 +525,7 @@ public: ...@@ -525,7 +525,7 @@ public:
//! Whether a parse error has occured in the last parsing. //! Whether a parse error has occured in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); } bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing. //! Get the \ref ParseErrorCode of last parsing.
ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
...@@ -585,7 +585,7 @@ private: ...@@ -585,7 +585,7 @@ private:
void ParseObject(InputStream& is, Handler& handler) { void ParseObject(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == '{'); RAPIDJSON_ASSERT(is.Peek() == '{');
is.Take(); // Skip '{' is.Take(); // Skip '{'
if (RAPIDJSON_UNLIKELY(!handler.StartObject())) if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
...@@ -628,12 +628,12 @@ private: ...@@ -628,12 +628,12 @@ private:
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break; break;
case '}': case '}':
is.Take(); is.Take();
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
default: default:
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
break; break;
} }
...@@ -654,10 +654,10 @@ private: ...@@ -654,10 +654,10 @@ private:
void ParseArray(InputStream& is, Handler& handler) { void ParseArray(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == '['); RAPIDJSON_ASSERT(is.Peek() == '[');
is.Take(); // Skip '[' is.Take(); // Skip '['
if (RAPIDJSON_UNLIKELY(!handler.StartArray())) if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
...@@ -780,7 +780,7 @@ private: ...@@ -780,7 +780,7 @@ private:
*stack_.template Push<Ch>() = c; *stack_.template Push<Ch>() = c;
++length_; ++length_;
} }
RAPIDJSON_FORCEINLINE void* Push(SizeType count) { RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
length_ += count; length_ += count;
return stack_.template Push<Ch>(count); return stack_.template Push<Ch>(count);
...@@ -838,10 +838,10 @@ private: ...@@ -838,10 +838,10 @@ private:
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = { static const char escape[256] = {
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
}; };
#undef Z16 #undef Z16
...@@ -893,8 +893,8 @@ private: ...@@ -893,8 +893,8 @@ private:
} }
else { else {
size_t offset = is.Tell(); size_t offset = is.Tell();
if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
!Transcoder<SEncoding, TEncoding>::Validate(is, os) : !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
!Transcoder<SEncoding, TEncoding>::Transcode(is, os)))) !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
} }
...@@ -954,7 +954,7 @@ private: ...@@ -954,7 +954,7 @@ private:
} }
_mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
} }
is.src_ = p; is.src_ = p;
} }
...@@ -977,7 +977,7 @@ private: ...@@ -977,7 +977,7 @@ private:
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
is.src_ = p; is.src_ = p;
is.dst_ = q; is.dst_ = q;
return; return;
} }
else else
*q++ = *p++; *q++ = *p++;
...@@ -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() {
...@@ -1101,9 +1101,9 @@ private: ...@@ -1101,9 +1101,9 @@ private:
return Base::is.Take(); return Base::is.Take();
} }
RAPIDJSON_FORCEINLINE void Push(char c) { RAPIDJSON_FORCEINLINE void Push(char c) {
stackStream.Put(c); stackStream.Put(c);
} }
size_t Length() { return stackStream.Length(); } size_t Length() { return stackStream.Length(); }
...@@ -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();
...@@ -1173,7 +1185,7 @@ private: ...@@ -1173,7 +1185,7 @@ private:
bool useDouble = false; bool useDouble = false;
double d = 0.0; double d = 0.0;
if (use64bit) { if (use64bit) {
if (minus) if (minus)
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
...@@ -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')))
...@@ -1223,7 +1232,7 @@ private: ...@@ -1223,7 +1232,7 @@ private:
// Use i64 to store significand in 64-bit architecture // Use i64 to store significand in 64-bit architecture
if (!use64bit) if (!use64bit)
i64 = i; i64 = i;
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
break; break;
...@@ -1260,11 +1269,7 @@ private: ...@@ -1260,11 +1269,7 @@ 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) ) { if (!useDouble) {
s.Push( 'e' );
}
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);
} }
} }
...@@ -1369,10 +1375,10 @@ private: ...@@ -1369,10 +1375,10 @@ private:
case '"': ParseString<parseFlags>(is, handler); break; case '"': ParseString<parseFlags>(is, handler); break;
case '{': ParseObject<parseFlags>(is, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray <parseFlags>(is, handler); break; case '[': ParseArray <parseFlags>(is, handler); break;
default : default :
ParseNumber<parseFlags>(is, handler); ParseNumber<parseFlags>(is, handler);
break; break;
} }
} }
...@@ -1444,7 +1450,7 @@ private: ...@@ -1444,7 +1450,7 @@ private:
#undef N #undef N
#undef N16 #undef N16
//!@endcond //!@endcond
if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]); return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
else else
...@@ -1775,7 +1781,7 @@ private: ...@@ -1775,7 +1781,7 @@ private:
// Error flag has been set. // Error flag has been set.
return; return;
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
...@@ -1788,7 +1794,7 @@ private: ...@@ -1788,7 +1794,7 @@ private:
case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
} }
} }
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
......
...@@ -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()
......
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#include "unittest.h" #include "unittest.h"
...@@ -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);
...@@ -297,7 +297,7 @@ static void TestParseDouble() { ...@@ -297,7 +297,7 @@ static void TestParseDouble() {
} }
// Cover trimming // Cover trimming
TEST_DOUBLE(fullPrecision, TEST_DOUBLE(fullPrecision,
"2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508" "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012" "7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306" "9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
...@@ -306,7 +306,7 @@ static void TestParseDouble() { ...@@ -306,7 +306,7 @@ static void TestParseDouble() {
"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844" "5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042" "2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901" "7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
"e-308", "e-308",
2.2250738585072014e-308); 2.2250738585072014e-308);
{ {
...@@ -457,12 +457,12 @@ template <typename Encoding> ...@@ -457,12 +457,12 @@ template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > { struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
ParseStringHandler() : str_(0), length_(0), copy_() {} ParseStringHandler() : str_(0), length_(0), copy_() {}
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); } ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
ParseStringHandler(const ParseStringHandler&); ParseStringHandler(const ParseStringHandler&);
ParseStringHandler& operator=(const ParseStringHandler&); ParseStringHandler& operator=(const ParseStringHandler&);
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool String(const typename Encoding::Ch* str, size_t length, bool copy) { bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
EXPECT_EQ(0, str_); EXPECT_EQ(0, str_);
if (copy) { if (copy) {
str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch))); str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch)));
...@@ -470,7 +470,7 @@ struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod ...@@ -470,7 +470,7 @@ struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod
} }
else else
str_ = str; str_ = str;
length_ = length; length_ = length;
copy_ = copy; copy_ = copy;
return true; return true;
} }
...@@ -499,7 +499,7 @@ TEST(Reader, ParseString) { ...@@ -499,7 +499,7 @@ TEST(Reader, ParseString) {
EXPECT_EQ(StrLen(e), h2.length_); \ EXPECT_EQ(StrLen(e), h2.length_); \
} }
// String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral. // String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
// And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch. // And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch.
// In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types. // In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types.
// Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch. // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch.
...@@ -650,7 +650,7 @@ TEST(Reader, ParseString_Error) { ...@@ -650,7 +650,7 @@ TEST(Reader, ParseString_Error) {
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
// 3 Malformed sequences // 3 Malformed sequences
// 3.1 Unexpected continuation bytes // 3.1 Unexpected continuation bytes
{ {
...@@ -684,19 +684,19 @@ TEST(Reader, ParseString_Error) { ...@@ -684,19 +684,19 @@ TEST(Reader, ParseString_Error) {
} }
} }
// 4 Overlong sequences // 4 Overlong sequences
// 4.1 Examples of an overlong ASCII character // 4.1 Examples of an overlong ASCII character
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
// 4.2 Maximum overlong sequences // 4.2 Maximum overlong sequences
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
// 4.3 Overlong representation of the NUL character // 4.3 Overlong representation of the NUL character
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
...@@ -790,14 +790,14 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> { ...@@ -790,14 +790,14 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } bool Null() { EXPECT_EQ(8u, step_); step_++; return true; }
bool Bool(bool b) { bool Bool(bool b) {
switch(step_) { switch(step_) {
case 4: EXPECT_TRUE(b); step_++; return true; case 4: EXPECT_TRUE(b); step_++; return true;
case 6: EXPECT_FALSE(b); step_++; return true; case 6: EXPECT_FALSE(b); step_++; return true;
default: ADD_FAILURE(); return false; default: ADD_FAILURE(); return false;
} }
} }
bool Int(int i) { bool Int(int i) {
switch(step_) { switch(step_) {
case 10: EXPECT_EQ(123, i); step_++; return true; case 10: EXPECT_EQ(123, i); step_++; return true;
case 15: EXPECT_EQ(1, i); step_++; return true; case 15: EXPECT_EQ(1, i); step_++; return true;
...@@ -808,7 +808,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> { ...@@ -808,7 +808,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
} }
bool Uint(unsigned i) { return Int(static_cast<int>(i)); } bool Uint(unsigned i) { return Int(static_cast<int>(i)); }
bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
bool String(const char* str, size_t, bool) { bool String(const char* str, size_t, bool) {
switch(step_) { switch(step_) {
case 1: EXPECT_STREQ("hello", str); step_++; return true; case 1: EXPECT_STREQ("hello", str); step_++; return true;
case 2: EXPECT_STREQ("world", str); step_++; return true; case 2: EXPECT_STREQ("world", str); step_++; return true;
...@@ -1045,7 +1045,7 @@ struct StreamTraits<CustomStringStream<Encoding> > { ...@@ -1045,7 +1045,7 @@ struct StreamTraits<CustomStringStream<Encoding> > {
}; };
} // namespace rapidjson } // namespace rapidjson
#endif #endif
TEST(Reader, CustomStringStream) { TEST(Reader, CustomStringStream) {
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
...@@ -1069,7 +1069,7 @@ public: ...@@ -1069,7 +1069,7 @@ public:
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c); return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
} }
Ch Take() { Ch Take() {
int c = is_.get(); int c = is_.get();
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c); return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
} }
...@@ -1097,7 +1097,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { ...@@ -1097,7 +1097,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) {
Reader reader; Reader reader;
ParseArrayHandler<4> h; ParseArrayHandler<4> h;
reader.Parse(is, h); reader.Parse(is, h);
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
} }
// Test iterative parsing. // Test iterative parsing.
...@@ -1195,7 +1195,7 @@ struct IterativeParsingReaderHandler { ...@@ -1195,7 +1195,7 @@ struct IterativeParsingReaderHandler {
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; } bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; } bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; }
bool EndObject(SizeType c) { bool EndObject(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity); RAPIDJSON_ASSERT(LogCount < LogCapacity);
Logs[LogCount++] = LOG_ENDOBJECT; Logs[LogCount++] = LOG_ENDOBJECT;
...@@ -1446,7 +1446,7 @@ TEST(Reader, ParseEmptyOnelineComment) { ...@@ -1446,7 +1446,7 @@ TEST(Reader, ParseEmptyOnelineComment) {
} }
TEST(Reader, ParseMultipleCommentsInARow) { TEST(Reader, ParseMultipleCommentsInARow) {
const char* json = const char* json =
"{/* first comment *//* second */\n" "{/* first comment *//* second */\n"
"/* third */ /*fourth*/// last one\n" "/* third */ /*fourth*/// last one\n"
"\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; "\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
...@@ -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; 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 = "{ \"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;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
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