Merge remote-tracking branch 'miloyip/master'
This commit is contained in:
commit
26e089b9a2
@ -18,6 +18,7 @@ set(EXAMPLES
|
||||
serialize
|
||||
simpledom
|
||||
simplereader
|
||||
simplepullreader
|
||||
simplewriter
|
||||
tutorial)
|
||||
|
||||
|
48
example/simplepullreader/simplepullreader.cpp
Normal file
48
example/simplepullreader/simplepullreader.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#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:
|
||||
template <typename T>
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::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
|
||||
|
@ -513,6 +513,83 @@ public:
|
||||
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.
|
||||
bool HasParseError() const { return parseResult_.IsError(); }
|
||||
|
||||
@ -1170,18 +1247,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<double>::quiet_NaN();
|
||||
if (Consume(s, 'N')) {
|
||||
if (Consume(s, 'a') && Consume(s, 'N')) {
|
||||
d = std::numeric_limits<double>::quiet_NaN();
|
||||
useNanOrInf = true;
|
||||
}
|
||||
}
|
||||
else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
|
||||
d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::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<double>::infinity() : std::numeric_limits<double>::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());
|
||||
@ -1393,30 +1479,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,
|
||||
@ -1467,6 +1555,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
|
||||
@ -1481,18 +1581,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
|
||||
@ -1521,20 +1609,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
|
||||
@ -1549,20 +1623,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,
|
||||
@ -1597,6 +1657,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)
|
||||
@ -1611,18 +1683,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<IterativeParsingState>(G[state][token]);
|
||||
@ -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>
|
||||
ParseResult IterativeParse(InputStream& is, Handler& handler) {
|
||||
parseResult_.Clear();
|
||||
ClearStackOnExit scope(*this);
|
||||
IterativeParsingState state = IterativeParsingStartState;
|
||||
|
||||
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
while (is.Peek() != '\0') {
|
||||
Token t = Tokenize(is.Peek());
|
||||
IterativeParsingState n = Predict(state, t);
|
||||
IterativeParsingState d = Transit<parseFlags>(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<parseFlags>(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<StackAllocator> 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.
|
||||
|
@ -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<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
|
||||
return v;\
|
||||
}
|
||||
|
||||
|
@ -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}";
|
||||
};
|
||||
}
|
@ -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)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream s(json_);
|
||||
|
@ -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<UTF8<>, 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<kParseIterativeFlag>(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<kParseDefaultFlags>(ss, h))
|
||||
break;
|
||||
}
|
||||
EXPECT_TRUE(reader.HasParseError()) << filename;
|
||||
|
||||
free(json);
|
||||
}
|
||||
|
||||
@ -87,12 +118,25 @@ TEST(JsonChecker, Reader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Test stack-based parsing.
|
||||
GenericDocument<UTF8<>, 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<kParseIterativeFlag>(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<kParseDefaultFlags>(ss, h))
|
||||
break;
|
||||
}
|
||||
EXPECT_FALSE(reader.HasParseError()) << filename;
|
||||
|
||||
free(json);
|
||||
}
|
||||
|
@ -1157,22 +1157,22 @@ template<typename Encoding = UTF8<> >
|
||||
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<int>(c);
|
||||
RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
|
||||
Logs[LogCount++] = LOG_ENDOBJECT | static_cast<uint32_t>(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<int>(c);
|
||||
RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
|
||||
Logs[LogCount++] = LOG_ENDARRAY | static_cast<uint32_t>(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<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.
|
||||
struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> {
|
||||
bool StartObject() { return false; }
|
||||
@ -1832,6 +1877,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", 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user