From 20f5caa8f64f3efaf6effb35f17d14dc9fcb3aab Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Thu, 2 Feb 2017 23:25:29 -0800 Subject: [PATCH 01/17] Token-by-token pull parsing Refactored the iterative parser so that users can parse a single JSON element at a time (invoking the handler one time) and then return control to the calling code. Call IterativeParseInit to start, and then call IterativeParseNext to retrieve one JSON element. Use IterativeParseComplete to check for JSON document completion. --- include/rapidjson/reader.h | 111 +++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 28 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index dbb5e16..68ef128 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -513,6 +513,68 @@ public: return Parse(is, handler); } + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult IterativeParseNext(InputStream& is, Handler& handler) { + while (is.Peek() != '\0') { + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return parseResult_; + } + + state_ = d; + + // Do not further consume streams if a root JSON has been parsed. + if (state_ == IterativeParsingFinishState) { + // If StopWhenDone is not set, and stray data is found post-root, flag an error. + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') + HandleError(state_, is); + } + return parseResult_; + } + + if (!IsIterativeParsingDelimiterState(n)) + return parseResult_; + } + + // Handle the end of file. + if (state_ != IterativeParsingFinishState) + HandleError(state_, is); + + stack_.Clear(); + return parseResult_; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + bool IterativeParseComplete() { + return IsIterativeParsingCompleteState(state_); + } + //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } @@ -1803,44 +1865,37 @@ private: } } + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { + const unsigned int delimiterStateMask = + (1 << IterativeParsingKeyValueDelimiterState) | + (1 << IterativeParsingMemberDelimiterState) | + (1 << IterativeParsingElementDelimiterState); + + return (1 << s) & delimiterStateMask; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { + const unsigned int completeStateMask = + (1 << IterativeParsingFinishState) | + (1 << IterativeParsingErrorState); + + return (1 << s) & completeStateMask; + } + template ParseResult IterativeParse(InputStream& is, Handler& handler) { - parseResult_.Clear(); - ClearStackOnExit scope(*this); - IterativeParsingState state = IterativeParsingStartState; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - while (is.Peek() != '\0') { - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state, t); - IterativeParsingState d = Transit(state, t, n, is, handler); - - if (d == IterativeParsingErrorState) { - HandleError(state, is); + IterativeParseInit(); + while (!IterativeParseComplete()) { + if (!IterativeParseNext(is, handler)) break; - } - - state = d; - - // Do not further consume streams if a root JSON has been parsed. - if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) - break; - - SkipWhitespaceAndComments(is); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } - - // Handle the end of file. - if (state != IterativeParsingFinishState) - HandleError(state, is); - return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; + IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. From 1a7c5ea5179601308a46a21a339a146d295af78e Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Fri, 3 Feb 2017 00:29:43 -0800 Subject: [PATCH 02/17] Fix Dev Studio bool-conversion warning --- include/rapidjson/reader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 68ef128..9babf75 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1871,7 +1871,7 @@ private: (1 << IterativeParsingMemberDelimiterState) | (1 << IterativeParsingElementDelimiterState); - return (1 << s) & delimiterStateMask; + return !!((1 << s) & delimiterStateMask); } RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { @@ -1879,7 +1879,7 @@ private: (1 << IterativeParsingFinishState) | (1 << IterativeParsingErrorState); - return (1 << s) & completeStateMask; + return !!((1 << s) & completeStateMask); } template From 5de7258478433bf76f998fdc6a0f326709aeabc5 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Fri, 3 Feb 2017 17:14:14 -0800 Subject: [PATCH 03/17] Improve performance Slight performance improvement over previous submission --- include/rapidjson/reader.h | 174 +++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 84 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 9babf75..065772f 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -529,9 +529,8 @@ public: \return Whether the parsing is successful. */ template - ParseResult IterativeParseNext(InputStream& is, Handler& handler) { + bool IterativeParseNext(InputStream& is, Handler& handler) { while (is.Peek() != '\0') { - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); SkipWhitespaceAndComments(is); Token t = Tokenize(is.Peek()); @@ -540,38 +539,52 @@ public: if (d == IterativeParsingErrorState) { HandleError(state_, is); - return parseResult_; + return false; } state_ = d; - // Do not further consume streams if a root JSON has been parsed. - if (state_ == IterativeParsingFinishState) { - // If StopWhenDone is not set, and stray data is found post-root, flag an error. + // Do not further consume streams if we've parsed a complete object or hit an error. + if (IsIterativeParsingCompleteState(state_)) { + // If we hit an error, we are done. + if (HasParseError()) + return false; + + // If StopWhenDone is not set... if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... SkipWhitespaceAndComments(is); - if (is.Peek() != '\0') + if (is.Peek() != '\0') { + // ... this is considered an error. HandleError(state_, is); + return false; + } } - return parseResult_; + + // We are done! + return true; } + // If we found anything other than a delimiter, we invoked the handler, so we can return true now. if (!IsIterativeParsingDelimiterState(n)) - return parseResult_; + return true; } - // Handle the end of file. - if (state_ != IterativeParsingFinishState) - HandleError(state_, is); - + // We reached the end of file. stack_.Clear(); - return parseResult_; + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; } //! Check if token-by-token parsing JSON text is complete /*! \return Whether the JSON has been fully decoded. */ - bool IterativeParseComplete() { + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { return IsIterativeParsingCompleteState(state_); } @@ -1455,30 +1468,32 @@ private: // States enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, - IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state - IterativeParsingValueState + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount }; - enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; - // Tokens enum Token { LeftBracketToken = 0, @@ -1529,6 +1544,18 @@ private: RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // Start { IterativeParsingArrayInitialState, // Left bracket @@ -1543,18 +1570,6 @@ private: IterativeParsingValueState, // Null IterativeParsingValueState // Number }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, // ObjectInitial { IterativeParsingErrorState, // Left bracket @@ -1583,20 +1598,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, // MemberValue { IterativeParsingErrorState, // Left bracket @@ -1611,20 +1612,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1659,6 +1646,18 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) @@ -1673,18 +1672,34 @@ private: IterativeParsingElementState, // Null IterativeParsingElementState // Number }, - // ArrayFinish(sink state) + // MemberDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number }, - // Single Value (sink state) + // KeyValueDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, }; // End of G return static_cast(G[state][token]); @@ -1866,20 +1881,11 @@ private: } RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { - const unsigned int delimiterStateMask = - (1 << IterativeParsingKeyValueDelimiterState) | - (1 << IterativeParsingMemberDelimiterState) | - (1 << IterativeParsingElementDelimiterState); - - return !!((1 << s) & delimiterStateMask); + return s >= IterativeParsingElementDelimiterState; } RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { - const unsigned int completeStateMask = - (1 << IterativeParsingFinishState) | - (1 << IterativeParsingErrorState); - - return !!((1 << s) & completeStateMask); + return s <= IterativeParsingErrorState; } template From 116f65994b928405149ddf38c4e8d6e1399a1e0b Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Fri, 3 Feb 2017 18:58:37 -0800 Subject: [PATCH 04/17] Improve coverage and performance Further improvement to perftest and hoping to make coveralls happy. --- include/rapidjson/reader.h | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 065772f..dcdc8cc 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -537,18 +537,17 @@ public: IterativeParsingState n = Predict(state_, t); IterativeParsingState d = Transit(state_, t, n, is, handler); - if (d == IterativeParsingErrorState) { - HandleError(state_, is); - return false; - } - - state_ = d; - - // Do not further consume streams if we've parsed a complete object or hit an error. - if (IsIterativeParsingCompleteState(state_)) { - // If we hit an error, we are done. - if (HasParseError()) + // If we've finished or hit an error... + if (IsIterativeParsingCompleteState(d)) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; // If StopWhenDone is not set... if (!(parseFlags & kParseStopWhenDoneFlag)) { @@ -561,11 +560,14 @@ public: } } - // We are done! + // Success! We are done! return true; } - // If we found anything other than a delimiter, we invoked the handler, so we can return true now. + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. if (!IsIterativeParsingDelimiterState(n)) return true; } From 82a423db7d9bbc65269ddb35436ea7a46bfd2140 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Fri, 3 Feb 2017 21:12:53 -0800 Subject: [PATCH 05/17] Added unit test for pull parsing New unit test which ensures that IterativeParseNext always generates exactly one element at a time, and that calling IterativeParseNext on a complete document is harmless and generates zero events. --- test/unittest/readertest.cpp | 101 +++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index ac5a067..b1c0c31 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1157,22 +1157,22 @@ template > struct IterativeParsingReaderHandler { typedef typename Encoding::Ch Ch; - const static int LOG_NULL = -1; - const static int LOG_BOOL = -2; - const static int LOG_INT = -3; - const static int LOG_UINT = -4; - const static int LOG_INT64 = -5; - const static int LOG_UINT64 = -6; - const static int LOG_DOUBLE = -7; - const static int LOG_STRING = -8; - const static int LOG_STARTOBJECT = -9; - const static int LOG_KEY = -10; - const static int LOG_ENDOBJECT = -11; - const static int LOG_STARTARRAY = -12; - const static int LOG_ENDARRAY = -13; + const static uint32_t LOG_NULL = 0x10000000; + const static uint32_t LOG_BOOL = 0x20000000; + const static uint32_t LOG_INT = 0x30000000; + const static uint32_t LOG_UINT = 0x40000000; + const static uint32_t LOG_INT64 = 0x50000000; + const static uint32_t LOG_UINT64 = 0x60000000; + const static uint32_t LOG_DOUBLE = 0x70000000; + const static uint32_t LOG_STRING = 0x80000000; + const static uint32_t LOG_STARTOBJECT = 0x90000000; + const static uint32_t LOG_KEY = 0xA0000000; + const static uint32_t LOG_ENDOBJECT = 0xB0000000; + const static uint32_t LOG_STARTARRAY = 0xC0000000; + const static uint32_t LOG_ENDARRAY = 0xD0000000; const static size_t LogCapacity = 256; - int Logs[LogCapacity]; + uint32_t Logs[LogCapacity]; size_t LogCount; IterativeParsingReaderHandler() : LogCount(0) { @@ -1202,8 +1202,8 @@ struct IterativeParsingReaderHandler { bool EndObject(SizeType c) { RAPIDJSON_ASSERT(LogCount < LogCapacity); - Logs[LogCount++] = LOG_ENDOBJECT; - Logs[LogCount++] = static_cast(c); + RAPIDJSON_ASSERT((static_cast(c) & 0xF0000000) == 0); + Logs[LogCount++] = LOG_ENDOBJECT | static_cast(c); return true; } @@ -1211,8 +1211,8 @@ struct IterativeParsingReaderHandler { bool EndArray(SizeType c) { RAPIDJSON_ASSERT(LogCount < LogCapacity); - Logs[LogCount++] = LOG_ENDARRAY; - Logs[LogCount++] = static_cast(c); + RAPIDJSON_ASSERT((static_cast(c) & 0xF0000000) == 0); + Logs[LogCount++] = LOG_ENDARRAY | static_cast(c); return true; } }; @@ -1228,7 +1228,7 @@ TEST(Reader, IterativeParsing_General) { EXPECT_FALSE(r.IsError()); EXPECT_FALSE(reader.HasParseError()); - int e[] = { + uint32_t e[] = { handler.LOG_STARTARRAY, handler.LOG_INT, handler.LOG_STARTOBJECT, @@ -1236,14 +1236,14 @@ TEST(Reader, IterativeParsing_General) { handler.LOG_STARTARRAY, handler.LOG_INT, handler.LOG_INT, - handler.LOG_ENDARRAY, 2, - handler.LOG_ENDOBJECT, 1, + handler.LOG_ENDARRAY | 2, + handler.LOG_ENDOBJECT | 1, handler.LOG_NULL, handler.LOG_BOOL, handler.LOG_BOOL, handler.LOG_STRING, handler.LOG_DOUBLE, - handler.LOG_ENDARRAY, 7 + handler.LOG_ENDARRAY | 7 }; EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); @@ -1265,20 +1265,20 @@ TEST(Reader, IterativeParsing_Count) { EXPECT_FALSE(r.IsError()); EXPECT_FALSE(reader.HasParseError()); - int e[] = { + uint32_t e[] = { handler.LOG_STARTARRAY, handler.LOG_STARTOBJECT, - handler.LOG_ENDOBJECT, 0, + handler.LOG_ENDOBJECT | 0, handler.LOG_STARTOBJECT, handler.LOG_KEY, handler.LOG_INT, - handler.LOG_ENDOBJECT, 1, + handler.LOG_ENDOBJECT | 1, handler.LOG_STARTARRAY, handler.LOG_INT, - handler.LOG_ENDARRAY, 1, + handler.LOG_ENDARRAY | 1, handler.LOG_STARTARRAY, - handler.LOG_ENDARRAY, 0, - handler.LOG_ENDARRAY, 4 + handler.LOG_ENDARRAY | 0, + handler.LOG_ENDARRAY | 4 }; EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); @@ -1289,6 +1289,51 @@ TEST(Reader, IterativeParsing_Count) { } } +TEST(Reader, IterativePullParsing_General) { + { + IterativeParsingReaderHandler<> handler; + uint32_t e[] = { + handler.LOG_STARTARRAY, + handler.LOG_INT, + handler.LOG_STARTOBJECT, + handler.LOG_KEY, + handler.LOG_STARTARRAY, + handler.LOG_INT, + handler.LOG_INT, + handler.LOG_ENDARRAY | 2, + handler.LOG_ENDOBJECT | 1, + handler.LOG_NULL, + handler.LOG_BOOL, + handler.LOG_BOOL, + handler.LOG_STRING, + handler.LOG_DOUBLE, + handler.LOG_ENDARRAY | 7 + }; + + StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); + Reader reader; + + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + size_t oldLogCount = handler.LogCount; + EXPECT_TRUE(oldLogCount < sizeof(e) / sizeof(int)) << "overrun"; + + EXPECT_TRUE(reader.IterativeParseNext(is, handler)) << "parse fail"; + EXPECT_EQ(handler.LogCount, oldLogCount + 1) << "handler should be invoked exactly once each time"; + EXPECT_EQ(e[oldLogCount], handler.Logs[oldLogCount]) << "wrong event returned"; + } + + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount) << "handler invoked wrong number of times"; + + // The handler should not be invoked when the JSON has been fully read, but it should not fail + size_t oldLogCount = handler.LogCount; + EXPECT_TRUE(reader.IterativeParseNext(is, handler)) << "parse-next past complete is allowed"; + EXPECT_EQ(handler.LogCount, oldLogCount) << "parse-next past complete should not invoke handler"; + EXPECT_FALSE(reader.HasParseError()) << "parse-next past complete should not generate parse error"; + } +} + // Test iterative parsing on kParseErrorTermination. struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> { bool StartObject() { return false; } From 4394b3bac7a0647f5121a533397c0fe20c89dab8 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Sat, 4 Feb 2017 00:05:34 -0800 Subject: [PATCH 06/17] Add LIKELY and UNLIKELY hints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doesn’t seem to affect timings in perftest on my machine, but it may help others. --- include/rapidjson/reader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index dcdc8cc..df59a1e 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -530,7 +530,7 @@ public: */ template bool IterativeParseNext(InputStream& is, Handler& handler) { - while (is.Peek() != '\0') { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { SkipWhitespaceAndComments(is); Token t = Tokenize(is.Peek()); @@ -538,7 +538,7 @@ public: IterativeParsingState d = Transit(state_, t, n, is, handler); // If we've finished or hit an error... - if (IsIterativeParsingCompleteState(d)) { + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { // Report errors. if (d == IterativeParsingErrorState) { HandleError(state_, is); From d84d5fe0551634d1057adf6eb163ce8a63d00f1a Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Sat, 4 Feb 2017 00:41:34 -0800 Subject: [PATCH 07/17] Add example SimplePullHandler code Example code to demonstrate how the token-pulling reader can be used. --- example/simplepullreader/simplepullreader.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 example/simplepullreader/simplepullreader.cpp diff --git a/example/simplepullreader/simplepullreader.cpp b/example/simplepullreader/simplepullreader.cpp new file mode 100644 index 0000000..0cce08b --- /dev/null +++ b/example/simplepullreader/simplepullreader.cpp @@ -0,0 +1,40 @@ +#include "rapidjson/reader.h" +#include + +using namespace rapidjson; +using namespace std; + +struct MyHandler { + const char* type; + std::string data; + + bool Null() { type = "Null"; data.clear(); return true; } + bool Bool(bool b) { type = "Bool"; data = b? "true": "false"; return true; } + bool Int(int i) { type = "Int"; data = std::to_string(i); return true; } + bool Uint(unsigned u) { type = "Uint"; data = std::to_string(u); return true; } + bool Int64(int64_t i) { type = "Int64"; data = std::to_string(i); return true; } + bool Uint64(uint64_t u) { type = "Uint64"; data = std::to_string(u); return true; } + bool Double(double d) { type = "Double"; data = std::to_string(d); return true; } + bool RawNumber(const char* str, SizeType length, bool) { type = "Number"; data = std::string(str, length); return true; } + bool String(const char* str, SizeType length, bool) { type = "String" data = std::string(str, length); return true; } + bool StartObject() { type = "StartObject"; data.clear(); return true; } + bool Key(const char* str, SizeType length, bool) { type = "Key" data = std::string(str, length); return true; } + bool EndObject(SizeType memberCount) { type = "EndObject"; data = std::to_string(memberCount); return true; } + bool StartArray() { type = "StartArray"; data.clear(); return true; } + bool EndArray(SizeType elementCount) { type = "EndArray"; data = std::to_string(elementCount); return true; } +}; + +int main() { + const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; + + MyHandler handler; + Reader reader; + StringStream ss(json); + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + reader.IterativeParseNext(ss, handler); + cout << handler.type << ": " << handler.data << endl; + } + + return 0; +} From 4232e407f40a3f2f3769234c1069ebccda43ea51 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Sat, 4 Feb 2017 00:47:43 -0800 Subject: [PATCH 08/17] Clean up example code --- example/CMakeLists.txt | 1 + example/simplepullreader/simplepullreader.cpp | 24 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index bec6a8c..e16e3c9 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -18,6 +18,7 @@ set(EXAMPLES serialize simpledom simplereader + simplepullreader simplewriter tutorial) diff --git a/example/simplepullreader/simplepullreader.cpp b/example/simplepullreader/simplepullreader.cpp index 0cce08b..af8d5a7 100644 --- a/example/simplepullreader/simplepullreader.cpp +++ b/example/simplepullreader/simplepullreader.cpp @@ -9,19 +9,19 @@ struct MyHandler { std::string data; bool Null() { type = "Null"; data.clear(); return true; } - bool Bool(bool b) { type = "Bool"; data = b? "true": "false"; return true; } - bool Int(int i) { type = "Int"; data = std::to_string(i); return true; } - bool Uint(unsigned u) { type = "Uint"; data = std::to_string(u); return true; } - bool Int64(int64_t i) { type = "Int64"; data = std::to_string(i); return true; } - bool Uint64(uint64_t u) { type = "Uint64"; data = std::to_string(u); return true; } - bool Double(double d) { type = "Double"; data = std::to_string(d); return true; } - bool RawNumber(const char* str, SizeType length, bool) { type = "Number"; data = std::string(str, length); return true; } - bool String(const char* str, SizeType length, bool) { type = "String" data = std::string(str, length); return true; } + bool Bool(bool b) { type = "Bool:"; data = b? "true": "false"; return true; } + bool Int(int i) { type = "Int:"; data = std::to_string(i); return true; } + bool Uint(unsigned u) { type = "Uint:"; data = std::to_string(u); return true; } + bool Int64(int64_t i) { type = "Int64:"; data = std::to_string(i); return true; } + bool Uint64(uint64_t u) { type = "Uint64:"; data = std::to_string(u); return true; } + bool Double(double d) { type = "Double:"; data = std::to_string(d); return true; } + bool RawNumber(const char* str, SizeType length, bool) { type = "Number:"; data = std::string(str, length); return true; } + bool String(const char* str, SizeType length, bool) { type = "String:"; data = std::string(str, length); return true; } bool StartObject() { type = "StartObject"; data.clear(); return true; } - bool Key(const char* str, SizeType length, bool) { type = "Key" data = std::string(str, length); return true; } - bool EndObject(SizeType memberCount) { type = "EndObject"; data = std::to_string(memberCount); return true; } + bool Key(const char* str, SizeType length, bool) { type = "Key:"; data = std::string(str, length); return true; } + bool EndObject(SizeType memberCount) { type = "EndObject:"; data = std::to_string(memberCount); return true; } bool StartArray() { type = "StartArray"; data.clear(); return true; } - bool EndArray(SizeType elementCount) { type = "EndArray"; data = std::to_string(elementCount); return true; } + bool EndArray(SizeType elementCount) { type = "EndArray:"; data = std::to_string(elementCount); return true; } }; int main() { @@ -33,7 +33,7 @@ int main() { reader.IterativeParseInit(); while (!reader.IterativeParseComplete()) { reader.IterativeParseNext(ss, handler); - cout << handler.type << ": " << handler.data << endl; + cout << handler.type << handler.data << endl; } return 0; From 6288d95d1e65d6a57c480dea9edc342b4b721507 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Sat, 4 Feb 2017 01:07:00 -0800 Subject: [PATCH 09/17] SimplePullReader C++98 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit std::to_string can’t be used because it requires C++11. --- example/simplepullreader/simplepullreader.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/example/simplepullreader/simplepullreader.cpp b/example/simplepullreader/simplepullreader.cpp index af8d5a7..0b11b40 100644 --- a/example/simplepullreader/simplepullreader.cpp +++ b/example/simplepullreader/simplepullreader.cpp @@ -1,27 +1,33 @@ #include "rapidjson/reader.h" #include +#include using namespace rapidjson; using namespace std; +// If you can require C++11, you could use std::to_string here +template std::string stringify(T x) { + return (std::stringstream() << x).str(); +} + struct MyHandler { const char* type; std::string data; bool Null() { type = "Null"; data.clear(); return true; } bool Bool(bool b) { type = "Bool:"; data = b? "true": "false"; return true; } - bool Int(int i) { type = "Int:"; data = std::to_string(i); return true; } - bool Uint(unsigned u) { type = "Uint:"; data = std::to_string(u); return true; } - bool Int64(int64_t i) { type = "Int64:"; data = std::to_string(i); return true; } - bool Uint64(uint64_t u) { type = "Uint64:"; data = std::to_string(u); return true; } - bool Double(double d) { type = "Double:"; data = std::to_string(d); return true; } + bool Int(int i) { type = "Int:"; data = stringify(i); return true; } + bool Uint(unsigned u) { type = "Uint:"; data = stringify(u); return true; } + bool Int64(int64_t i) { type = "Int64:"; data = stringify(i); return true; } + bool Uint64(uint64_t u) { type = "Uint64:"; data = stringify(u); return true; } + bool Double(double d) { type = "Double:"; data = stringify(d); return true; } bool RawNumber(const char* str, SizeType length, bool) { type = "Number:"; data = std::string(str, length); return true; } bool String(const char* str, SizeType length, bool) { type = "String:"; data = std::string(str, length); return true; } bool StartObject() { type = "StartObject"; data.clear(); return true; } bool Key(const char* str, SizeType length, bool) { type = "Key:"; data = std::string(str, length); return true; } - bool EndObject(SizeType memberCount) { type = "EndObject:"; data = std::to_string(memberCount); return true; } + bool EndObject(SizeType memberCount) { type = "EndObject:"; data = stringify(memberCount); return true; } bool StartArray() { type = "StartArray"; data.clear(); return true; } - bool EndArray(SizeType elementCount) { type = "EndArray:"; data = std::to_string(elementCount); return true; } + bool EndArray(SizeType elementCount) { type = "EndArray:"; data = stringify(elementCount); return true; } }; int main() { From a11ec697969eb776973c680d1eadf9ab11ac7e7b Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Sat, 4 Feb 2017 01:18:46 -0800 Subject: [PATCH 10/17] More C++98 fixes --- example/simplepullreader/simplepullreader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/example/simplepullreader/simplepullreader.cpp b/example/simplepullreader/simplepullreader.cpp index 0b11b40..98566e6 100644 --- a/example/simplepullreader/simplepullreader.cpp +++ b/example/simplepullreader/simplepullreader.cpp @@ -7,7 +7,9 @@ using namespace std; // If you can require C++11, you could use std::to_string here template std::string stringify(T x) { - return (std::stringstream() << x).str(); + std::stringstream ss; + ss << x; + return ss.str(); } struct MyHandler { From 0f8389e78779cf13e5f0c8f4da2a3a780d097d42 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Tue, 7 Feb 2017 00:02:08 -0800 Subject: [PATCH 11/17] Restored original IterativeParse implementation Runs about 1-2% faster (original speed) by running in a tight loop, at the expense of slight code duplication with IterativeParseNext. --- include/rapidjson/reader.h | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index df59a1e..d92d9fb 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1892,11 +1892,36 @@ private: template ParseResult IterativeParse(InputStream& is, Handler& handler) { - IterativeParseInit(); - while (!IterativeParseComplete()) { - if (!IterativeParseNext(is, handler)) + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state, is); break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + return parseResult_; } From bd4c282d77d4bb6f0034405a721a6fbf477b4955 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Tue, 7 Feb 2017 01:08:51 -0800 Subject: [PATCH 12/17] Test coverage up Add more tests! Good for coverage. --- test/perftest/rapidjsontest.cpp | 29 ++++++++++++++++++++ test/unittest/jsoncheckertest.cpp | 44 +++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 675db31..f14e702 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -152,6 +152,35 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativeInsitu_DummyHandler)) { } } +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativePull_DummyHandler)) { + for (size_t i = 0; i < kTrialCount; i++) { + StringStream s(json_); + BaseReaderHandler<> h; + Reader reader; + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + if (!reader.IterativeParseNext(s, h)) + break; + } + EXPECT_FALSE(reader.HasParseError()); + } +} + +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativePullInsitu_DummyHandler)) { + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + InsituStringStream s(temp_); + BaseReaderHandler<> h; + Reader reader; + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + if (!reader.IterativeParseNext(s, h)) + break; + } + EXPECT_FALSE(reader.HasParseError()); + } +} + TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) { for (size_t i = 0; i < kTrialCount; i++) { StringStream s(json_); diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index e8f8526..47c2b56 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -48,6 +48,24 @@ static char* ReadFile(const char* filename, size_t& length) { return json; } +struct NoOpHandler { + bool Null() { return true; } + bool Bool(bool) { return true; } + bool Int(int) { return true; } + bool Uint(unsigned) { return true; } + bool Int64(int64_t) { return true; } + bool Uint64(uint64_t) { return true; } + bool Double(double) { return true; } + bool RawNumber(const char*, SizeType, bool) { return true; } + bool String(const char*, SizeType, bool) { return true; } + bool StartObject() { return true; } + bool Key(const char*, SizeType, bool) { return true; } + bool EndObject(SizeType) { return true; } + bool StartArray() { return true; } + bool EndArray(SizeType) { return true; } +}; + + TEST(JsonChecker, Reader) { char filename[256]; @@ -67,13 +85,26 @@ TEST(JsonChecker, Reader) { continue; } + // Test stack-based parsing. GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) document.Parse(json); EXPECT_TRUE(document.HasParseError()) << filename; + // Test iterative parsing. document.Parse(json); EXPECT_TRUE(document.HasParseError()) << filename; + // Test iterative pull-parsing. + Reader reader; + StringStream ss(json); + NoOpHandler h; + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + if (!reader.IterativeParseNext(ss, h)) + break; + } + EXPECT_TRUE(reader.HasParseError()) << filename; + free(json); } @@ -87,12 +118,25 @@ TEST(JsonChecker, Reader) { continue; } + // Test stack-based parsing. GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) document.Parse(json); EXPECT_FALSE(document.HasParseError()) << filename; + // Test iterative parsing. document.Parse(json); EXPECT_FALSE(document.HasParseError()) << filename; + + // Test iterative pull-parsing. + Reader reader; + StringStream ss(json); + NoOpHandler h; + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + if (!reader.IterativeParseNext(ss, h)) + break; + } + EXPECT_FALSE(reader.HasParseError()) << filename; free(json); } From c4117c68ccf45e2f80ea7693766db0c771b6d508 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Wed, 22 Feb 2017 21:54:31 -0800 Subject: [PATCH 13/17] Put in unit tests to catch parser failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed that the reader could over-consume “NaN” if token terminated in the middle. --- test/unittest/readertest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index ac5a067..0973791 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1832,6 +1832,10 @@ TEST(Reader, ParseNanAndInfinity) { TEST_NAN_INF("Infinity", inf); TEST_NAN_INF("-Inf", -inf); TEST_NAN_INF("-Infinity", -inf); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1); From 5e785d3db20cdad256a7c0139001b484ea37fab9 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Thu, 23 Feb 2017 00:11:12 -0800 Subject: [PATCH 14/17] Fix parsing of NaN/Inf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A failed half-consume of “NaN” now returns “value invalid” instead of attempting to consume an “Inf”. --- include/rapidjson/reader.h | 27 ++++++++++++++++++--------- test/unittest/readertest.cpp | 4 ++-- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index dbb5e16..c1d10e8 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1170,18 +1170,27 @@ private: } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - useNanOrInf = true; - if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { - d = std::numeric_limits::quiet_NaN(); + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } } - else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } } - else + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 0973791..2217a12 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1833,9 +1833,9 @@ TEST(Reader, ParseNanAndInfinity) { TEST_NAN_INF("-Inf", -inf); TEST_NAN_INF("-Infinity", -inf); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1); - TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 2); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 1); - TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 2); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1); From b977fd3c9d21c758d3cf74778458d573d3897b33 Mon Sep 17 00:00:00 2001 From: ylavic Date: Fri, 24 Feb 2017 16:46:53 +0100 Subject: [PATCH 15/17] Missing "internal" namespace for StrLen include/rapidjson/pointer.h:243:40: error: 'StrLen' was not declared in this scope return Append(name, StrLen(name), allocator); --- include/rapidjson/pointer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index bc7acfd..0f377ef 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -240,7 +240,7 @@ public: template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); + return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING From 5f92c3926b185dcaf95aaa9e524f573adbfeed36 Mon Sep 17 00:00:00 2001 From: oviradoi Date: Fri, 24 Feb 2017 19:50:36 +0200 Subject: [PATCH 16/17] Fix creating the nuget package with Raggles' fork of CoApp --- rapidjson.autopkg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rapidjson.autopkg b/rapidjson.autopkg index 70eb0d8..486ad14 100644 --- a/rapidjson.autopkg +++ b/rapidjson.autopkg @@ -71,5 +71,7 @@ Changed targets { // We're trying to be standard about these sorts of thing. (Will help with config.h later :D) //Defines += HAS_EQCORE; + // Fix creating the package with Raggles' fork of CoApp + Includes += "$(MSBuildThisFileDirectory)../..${d_include}"; }; } \ No newline at end of file From 97e2f7f16f3b739a262f1391478be484e6cac8ba Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 28 Feb 2017 09:48:36 +0800 Subject: [PATCH 17/17] Try fixing Error compilation Ubuntu 14.04 #834 --- include/rapidjson/schema.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 3f81d9b..c20a838 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -880,7 +880,7 @@ public: #define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ return v;\ }