Commit 26e089b9 authored by StilesCrisis's avatar StilesCrisis

Merge remote-tracking branch 'miloyip/master'

parents 933eb839 97e2f7f1
...@@ -18,6 +18,7 @@ set(EXAMPLES ...@@ -18,6 +18,7 @@ set(EXAMPLES
serialize serialize
simpledom simpledom
simplereader simplereader
simplepullreader
simplewriter simplewriter
tutorial) tutorial)
......
#include "rapidjson/reader.h"
#include <iostream>
#include <sstream>
using namespace rapidjson;
using namespace std;
// If you can require C++11, you could use std::to_string here
template <typename T> std::string stringify(T x) {
std::stringstream ss;
ss << x;
return ss.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 = 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 = stringify(memberCount); return true; }
bool StartArray() { type = "StartArray"; data.clear(); return true; }
bool EndArray(SizeType elementCount) { type = "EndArray:"; data = stringify(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<kParseDefaultFlags>(ss, handler);
cout << handler.type << handler.data << endl;
}
return 0;
}
...@@ -240,7 +240,7 @@ public: ...@@ -240,7 +240,7 @@ public:
template <typename T> template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer)) RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
Append(T* name, Allocator* allocator = 0) const { Append(T* name, Allocator* allocator = 0) const {
return Append(name, StrLen(name), allocator); return Append(name, internal::StrLen(name), allocator);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
......
...@@ -513,6 +513,83 @@ public: ...@@ -513,6 +513,83 @@ public:
return Parse<kParseDefaultFlags>(is, handler); return Parse<kParseDefaultFlags>(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 <unsigned parseFlags, typename InputStream, typename Handler>
bool IterativeParseNext(InputStream& is, Handler& handler) {
while (RAPIDJSON_LIKELY(is.Peek() != '\0')) {
SkipWhitespaceAndComments<parseFlags>(is);
Token t = Tokenize(is.Peek());
IterativeParsingState n = Predict(state_, t);
IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);
// If we've finished or hit an error...
if (RAPIDJSON_UNLIKELY(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)) {
// ... and extra non-whitespace data is found...
SkipWhitespaceAndComments<parseFlags>(is);
if (is.Peek() != '\0') {
// ... this is considered an error.
HandleError(state_, is);
return false;
}
}
// Success! We are done!
return true;
}
// 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;
}
// We reached the end of file.
stack_.Clear();
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.
*/
RAPIDJSON_FORCEINLINE bool IterativeParseComplete() {
return IsIterativeParsingCompleteState(state_);
}
//! 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(); }
...@@ -1170,18 +1247,27 @@ private: ...@@ -1170,18 +1247,27 @@ private:
} }
// Parse NaN or Infinity here // Parse NaN or Infinity here
else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
useNanOrInf = true; if (Consume(s, 'N')) {
if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { if (Consume(s, 'a') && Consume(s, 'N')) {
d = std::numeric_limits<double>::quiet_NaN(); d = std::numeric_limits<double>::quiet_NaN();
useNanOrInf = true;
}
} }
else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) {
d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity()); if (Consume(s, 'n') && Consume(s, 'f')) {
if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
&& Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) useNanOrInf = true;
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
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()); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
}
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
...@@ -1393,30 +1479,32 @@ private: ...@@ -1393,30 +1479,32 @@ private:
// States // States
enum IterativeParsingState { enum IterativeParsingState {
IterativeParsingStartState = 0, IterativeParsingFinishState = 0, // sink states at top
IterativeParsingFinishState, IterativeParsingErrorState, // sink states at top
IterativeParsingErrorState, IterativeParsingStartState,
// Object states // Object states
IterativeParsingObjectInitialState, IterativeParsingObjectInitialState,
IterativeParsingMemberKeyState, IterativeParsingMemberKeyState,
IterativeParsingKeyValueDelimiterState,
IterativeParsingMemberValueState, IterativeParsingMemberValueState,
IterativeParsingMemberDelimiterState,
IterativeParsingObjectFinishState, IterativeParsingObjectFinishState,
// Array states // Array states
IterativeParsingArrayInitialState, IterativeParsingArrayInitialState,
IterativeParsingElementState, IterativeParsingElementState,
IterativeParsingElementDelimiterState,
IterativeParsingArrayFinishState, IterativeParsingArrayFinishState,
// Single value state // Single value state
IterativeParsingValueState IterativeParsingValueState,
// Delimiter states (at bottom)
IterativeParsingElementDelimiterState,
IterativeParsingMemberDelimiterState,
IterativeParsingKeyValueDelimiterState,
cIterativeParsingStateCount
}; };
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
// Tokens // Tokens
enum Token { enum Token {
LeftBracketToken = 0, LeftBracketToken = 0,
...@@ -1467,6 +1555,18 @@ private: ...@@ -1467,6 +1555,18 @@ private:
RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
// current state x one lookahead token -> new state // current state x one lookahead token -> new state
static const char G[cIterativeParsingStateCount][kTokenCount] = { 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 // Start
{ {
IterativeParsingArrayInitialState, // Left bracket IterativeParsingArrayInitialState, // Left bracket
...@@ -1481,18 +1581,6 @@ private: ...@@ -1481,18 +1581,6 @@ private:
IterativeParsingValueState, // Null IterativeParsingValueState, // Null
IterativeParsingValueState // Number 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 // ObjectInitial
{ {
IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Left bracket
...@@ -1521,20 +1609,6 @@ private: ...@@ -1521,20 +1609,6 @@ private:
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number 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 // MemberValue
{ {
IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Left bracket
...@@ -1549,20 +1623,6 @@ private: ...@@ -1549,20 +1623,6 @@ private:
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number 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) // ObjectFinish(sink state)
{ {
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
...@@ -1597,6 +1657,18 @@ private: ...@@ -1597,6 +1657,18 @@ private:
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number 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 // ElementDelimiter
{ {
IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayInitialState, // Left bracket(push Element state)
...@@ -1611,18 +1683,34 @@ private: ...@@ -1611,18 +1683,34 @@ private:
IterativeParsingElementState, // Null IterativeParsingElementState, // Null
IterativeParsingElementState // Number IterativeParsingElementState // Number
}, },
// ArrayFinish(sink state) // MemberDelimiter
{ {
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, // Left bracket
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, // Right bracket
IterativeParsingErrorState 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, IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, // Right bracket
IterativeParsingErrorState 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 }; // End of G
return static_cast<IterativeParsingState>(G[state][token]); return static_cast<IterativeParsingState>(G[state][token]);
...@@ -1803,44 +1891,53 @@ private: ...@@ -1803,44 +1891,53 @@ private:
} }
} }
RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) {
return s >= IterativeParsingElementDelimiterState;
}
RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) {
return s <= IterativeParsingErrorState;
}
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
ParseResult IterativeParse(InputStream& is, Handler& handler) { ParseResult IterativeParse(InputStream& is, Handler& handler) {
parseResult_.Clear(); parseResult_.Clear();
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
IterativeParsingState state = IterativeParsingStartState; IterativeParsingState state = IterativeParsingStartState;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
while (is.Peek() != '\0') { while (is.Peek() != '\0') {
Token t = Tokenize(is.Peek()); Token t = Tokenize(is.Peek());
IterativeParsingState n = Predict(state, t); IterativeParsingState n = Predict(state, t);
IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler); IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
if (d == IterativeParsingErrorState) { if (d == IterativeParsingErrorState) {
HandleError(state, is); HandleError(state, is);
break; break;
} }
state = d; state = d;
// Do not further consume streams if a root JSON has been parsed. // Do not further consume streams if a root JSON has been parsed.
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
break; break;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
// Handle the end of file. // Handle the end of file.
if (state != IterativeParsingFinishState) if (state != IterativeParsingFinishState)
HandleError(state, is); HandleError(state, is);
return parseResult_; return parseResult_;
} }
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
ParseResult parseResult_; ParseResult parseResult_;
IterativeParsingState state_;
}; // class GenericReader }; // class GenericReader
//! Reader with UTF8 encoding and default allocator. //! Reader with UTF8 encoding and default allocator.
......
...@@ -880,7 +880,7 @@ public: ...@@ -880,7 +880,7 @@ public:
#define RAPIDJSON_STRING_(name, ...) \ #define RAPIDJSON_STRING_(name, ...) \
static const ValueType& Get##name##String() {\ static const ValueType& Get##name##String() {\
static const Ch s[] = { __VA_ARGS__, '\0' };\ static const Ch s[] = { __VA_ARGS__, '\0' };\
static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
return v;\ return v;\
} }
......
...@@ -71,5 +71,7 @@ Changed ...@@ -71,5 +71,7 @@ Changed
targets { targets {
// We're trying to be standard about these sorts of thing. (Will help with config.h later :D) // We're trying to be standard about these sorts of thing. (Will help with config.h later :D)
//Defines += HAS_EQCORE; //Defines += HAS_EQCORE;
// Fix creating the package with Raggles' fork of CoApp
Includes += "$(MSBuildThisFileDirectory)../..${d_include}";
}; };
} }
\ No newline at end of file
...@@ -152,6 +152,35 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativeInsitu_DummyHandler)) { ...@@ -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<kParseDefaultFlags>(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<kParseDefaultFlags|kParseInsituFlag>(s, h))
break;
}
EXPECT_FALSE(reader.HasParseError());
}
}
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) { TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) {
for (size_t i = 0; i < kTrialCount; i++) { for (size_t i = 0; i < kTrialCount; i++) {
StringStream s(json_); StringStream s(json_);
......
...@@ -48,6 +48,24 @@ static char* ReadFile(const char* filename, size_t& length) { ...@@ -48,6 +48,24 @@ static char* ReadFile(const char* filename, size_t& length) {
return json; 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) { TEST(JsonChecker, Reader) {
char filename[256]; char filename[256];
...@@ -67,13 +85,26 @@ TEST(JsonChecker, Reader) { ...@@ -67,13 +85,26 @@ TEST(JsonChecker, Reader) {
continue; continue;
} }
// Test stack-based parsing.
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
document.Parse(json); document.Parse(json);
EXPECT_TRUE(document.HasParseError()) << filename; EXPECT_TRUE(document.HasParseError()) << filename;
// Test iterative parsing.
document.Parse<kParseIterativeFlag>(json); document.Parse<kParseIterativeFlag>(json);
EXPECT_TRUE(document.HasParseError()) << filename; EXPECT_TRUE(document.HasParseError()) << filename;
// Test iterative pull-parsing.
Reader reader;
StringStream ss(json);
NoOpHandler h;
reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) {
if (!reader.IterativeParseNext<kParseDefaultFlags>(ss, h))
break;
}
EXPECT_TRUE(reader.HasParseError()) << filename;
free(json); free(json);
} }
...@@ -87,12 +118,25 @@ TEST(JsonChecker, Reader) { ...@@ -87,12 +118,25 @@ TEST(JsonChecker, Reader) {
continue; continue;
} }
// Test stack-based parsing.
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
document.Parse(json); document.Parse(json);
EXPECT_FALSE(document.HasParseError()) << filename; EXPECT_FALSE(document.HasParseError()) << filename;
// Test iterative parsing.
document.Parse<kParseIterativeFlag>(json); document.Parse<kParseIterativeFlag>(json);
EXPECT_FALSE(document.HasParseError()) << filename; EXPECT_FALSE(document.HasParseError()) << filename;
// Test iterative pull-parsing.
Reader reader;
StringStream ss(json);
NoOpHandler h;
reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) {
if (!reader.IterativeParseNext<kParseDefaultFlags>(ss, h))
break;
}
EXPECT_FALSE(reader.HasParseError()) << filename;
free(json); free(json);
} }
......
...@@ -1157,22 +1157,22 @@ template<typename Encoding = UTF8<> > ...@@ -1157,22 +1157,22 @@ template<typename Encoding = UTF8<> >
struct IterativeParsingReaderHandler { struct IterativeParsingReaderHandler {
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
const static int LOG_NULL = -1; const static uint32_t LOG_NULL = 0x10000000;
const static int LOG_BOOL = -2; const static uint32_t LOG_BOOL = 0x20000000;
const static int LOG_INT = -3; const static uint32_t LOG_INT = 0x30000000;
const static int LOG_UINT = -4; const static uint32_t LOG_UINT = 0x40000000;
const static int LOG_INT64 = -5; const static uint32_t LOG_INT64 = 0x50000000;
const static int LOG_UINT64 = -6; const static uint32_t LOG_UINT64 = 0x60000000;
const static int LOG_DOUBLE = -7; const static uint32_t LOG_DOUBLE = 0x70000000;
const static int LOG_STRING = -8; const static uint32_t LOG_STRING = 0x80000000;
const static int LOG_STARTOBJECT = -9; const static uint32_t LOG_STARTOBJECT = 0x90000000;
const static int LOG_KEY = -10; const static uint32_t LOG_KEY = 0xA0000000;
const static int LOG_ENDOBJECT = -11; const static uint32_t LOG_ENDOBJECT = 0xB0000000;
const static int LOG_STARTARRAY = -12; const static uint32_t LOG_STARTARRAY = 0xC0000000;
const static int LOG_ENDARRAY = -13; const static uint32_t LOG_ENDARRAY = 0xD0000000;
const static size_t LogCapacity = 256; const static size_t LogCapacity = 256;
int Logs[LogCapacity]; uint32_t Logs[LogCapacity];
size_t LogCount; size_t LogCount;
IterativeParsingReaderHandler() : LogCount(0) { IterativeParsingReaderHandler() : LogCount(0) {
...@@ -1202,8 +1202,8 @@ struct IterativeParsingReaderHandler { ...@@ -1202,8 +1202,8 @@ struct IterativeParsingReaderHandler {
bool EndObject(SizeType c) { bool EndObject(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity); RAPIDJSON_ASSERT(LogCount < LogCapacity);
Logs[LogCount++] = LOG_ENDOBJECT; RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
Logs[LogCount++] = static_cast<int>(c); Logs[LogCount++] = LOG_ENDOBJECT | static_cast<uint32_t>(c);
return true; return true;
} }
...@@ -1211,8 +1211,8 @@ struct IterativeParsingReaderHandler { ...@@ -1211,8 +1211,8 @@ struct IterativeParsingReaderHandler {
bool EndArray(SizeType c) { bool EndArray(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity); RAPIDJSON_ASSERT(LogCount < LogCapacity);
Logs[LogCount++] = LOG_ENDARRAY; RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
Logs[LogCount++] = static_cast<int>(c); Logs[LogCount++] = LOG_ENDARRAY | static_cast<uint32_t>(c);
return true; return true;
} }
}; };
...@@ -1228,7 +1228,7 @@ TEST(Reader, IterativeParsing_General) { ...@@ -1228,7 +1228,7 @@ TEST(Reader, IterativeParsing_General) {
EXPECT_FALSE(r.IsError()); EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
int e[] = { uint32_t e[] = {
handler.LOG_STARTARRAY, handler.LOG_STARTARRAY,
handler.LOG_INT, handler.LOG_INT,
handler.LOG_STARTOBJECT, handler.LOG_STARTOBJECT,
...@@ -1236,14 +1236,14 @@ TEST(Reader, IterativeParsing_General) { ...@@ -1236,14 +1236,14 @@ TEST(Reader, IterativeParsing_General) {
handler.LOG_STARTARRAY, handler.LOG_STARTARRAY,
handler.LOG_INT, handler.LOG_INT,
handler.LOG_INT, handler.LOG_INT,
handler.LOG_ENDARRAY, 2, handler.LOG_ENDARRAY | 2,
handler.LOG_ENDOBJECT, 1, handler.LOG_ENDOBJECT | 1,
handler.LOG_NULL, handler.LOG_NULL,
handler.LOG_BOOL, handler.LOG_BOOL,
handler.LOG_BOOL, handler.LOG_BOOL,
handler.LOG_STRING, handler.LOG_STRING,
handler.LOG_DOUBLE, handler.LOG_DOUBLE,
handler.LOG_ENDARRAY, 7 handler.LOG_ENDARRAY | 7
}; };
EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
...@@ -1265,20 +1265,20 @@ TEST(Reader, IterativeParsing_Count) { ...@@ -1265,20 +1265,20 @@ TEST(Reader, IterativeParsing_Count) {
EXPECT_FALSE(r.IsError()); EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
int e[] = { uint32_t e[] = {
handler.LOG_STARTARRAY, handler.LOG_STARTARRAY,
handler.LOG_STARTOBJECT, handler.LOG_STARTOBJECT,
handler.LOG_ENDOBJECT, 0, handler.LOG_ENDOBJECT | 0,
handler.LOG_STARTOBJECT, handler.LOG_STARTOBJECT,
handler.LOG_KEY, handler.LOG_KEY,
handler.LOG_INT, handler.LOG_INT,
handler.LOG_ENDOBJECT, 1, handler.LOG_ENDOBJECT | 1,
handler.LOG_STARTARRAY, handler.LOG_STARTARRAY,
handler.LOG_INT, handler.LOG_INT,
handler.LOG_ENDARRAY, 1, handler.LOG_ENDARRAY | 1,
handler.LOG_STARTARRAY, handler.LOG_STARTARRAY,
handler.LOG_ENDARRAY, 0, handler.LOG_ENDARRAY | 0,
handler.LOG_ENDARRAY, 4 handler.LOG_ENDARRAY | 4
}; };
EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
...@@ -1289,6 +1289,51 @@ TEST(Reader, IterativeParsing_Count) { ...@@ -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<kParseDefaultFlags>(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<kParseDefaultFlags>(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. // Test iterative parsing on kParseErrorTermination.
struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> { struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> {
bool StartObject() { return false; } bool StartObject() { return false; }
...@@ -1832,6 +1877,10 @@ TEST(Reader, ParseNanAndInfinity) { ...@@ -1832,6 +1877,10 @@ TEST(Reader, ParseNanAndInfinity) {
TEST_NAN_INF("Infinity", inf); TEST_NAN_INF("Infinity", inf);
TEST_NAN_INF("-Inf", -inf); TEST_NAN_INF("-Inf", -inf);
TEST_NAN_INF("-Infinity", -inf); TEST_NAN_INF("-Infinity", -inf);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 2);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 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); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1);
......
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