Commit 26e089b9 authored by StilesCrisis's avatar StilesCrisis

Merge remote-tracking branch 'miloyip/master'

parents 933eb839 97e2f7f1
......@@ -18,6 +18,7 @@ set(EXAMPLES
serialize
simpledom
simplereader
simplepullreader
simplewriter
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:
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,19 +1247,28 @@ 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'))) {
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'))) {
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'))))
&& 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,29 +1479,31 @@ 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,
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
// Delimiter states (at bottom)
IterativeParsingElementDelimiterState,
IterativeParsingMemberDelimiterState,
IterativeParsingKeyValueDelimiterState,
cIterativeParsingStateCount
};
// Tokens
enum Token {
......@@ -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,6 +1891,14 @@ 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();
......@@ -1841,6 +1937,7 @@ private:
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}";
};
}
\ No newline at end of file
......@@ -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,13 +118,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_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);
......
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