From 0b8adabab7f32dd9addc517aeb4c32b9da37e411 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 29 Sep 2017 09:44:05 +0800 Subject: [PATCH 01/36] Fix #1071 gitbook link --- readme.md | 2 +- readme.zh-cn.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index be22e20..b833a98 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON Documentation * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. ## Build status diff --git a/readme.zh-cn.md b/readme.zh-cn.md index bca8897..f4ddaa8 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON 文档 * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 ## Build 状态 From 2a0bc6062b38ed40586bd8e1945835698b95a9c1 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 29 Sep 2017 09:53:00 +0800 Subject: [PATCH 02/36] Update gitbook zh-cn link --- readme.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.zh-cn.md b/readme.zh-cn.md index f4ddaa8..ccf1669 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON 文档 * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/details/zh-cn) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 ## Build 状态 From b16ff281f854564e2669b2c3f4871793ddc51fc3 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Tue, 26 Sep 2017 15:39:06 +0800 Subject: [PATCH 03/36] Add feature of locating line and column number of error --- include/rapidjson/document.h | 11 ++++++++- include/rapidjson/error/error.h | 8 +++++++ include/rapidjson/stream.h | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 93b091f..de65740 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2219,14 +2219,17 @@ public: \return The document itself for fluent API. */ template - GenericDocument& ParseStream(InputStream& is) { + GenericDocument& ParseStream(InputStream& is_) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); + GenericStreamWrapper is(is_); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } else { + parseResult_.SetPos(is.line_, is.col_); } return *this; } @@ -2355,6 +2358,12 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorLine() const { return parseResult_.Line(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorColumn() const { return parseResult_.Col(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 9311d2f..be80579 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -116,6 +116,10 @@ public: ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } + //! Get the position of line number if error exists. + size_t Line() const { return line_; } + //! Get the position of column number if error exists. + size_t Col() const { return col_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } @@ -134,10 +138,14 @@ public: void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + //! Update line number and column number of the error position + void SetPos(size_t line, size_t col) { line_ = line; col_ = col; } private: ParseErrorCode code_; size_t offset_; + size_t line_; + size_t col_; }; //! Function pointer type of GetParseError(). diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index fef82c2..4e4ba80 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -100,6 +100,48 @@ inline void PutN(Stream& stream, Ch c, size_t n) { PutUnsafe(stream, c); } +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is designed for counting line and column number + \tof the error (if exists) position, while just forwarding any received + \tmessage to the origin stream. + \note implements Stream concept +*/ +template +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + size_t line_; + size_t col_; + GenericStreamWrapper(InputStream& is): is_(is), line_(1), col_(0) {} + + Ch Peek() const { return is_.Peek(); } + + // counting line and column number + Ch Take() { + Ch ch = is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + size_t Tell() { return is_.Tell(); } + + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { return is_.Put(ch); } + void Flush() { return is_.Flush(); } + size_t PutEnd(Ch* ch) { is_.PutEnd(ch); } + + const Ch* Peek4() const { is_.Peek4(); } +private: + InputStream& is_; +}; + /////////////////////////////////////////////////////////////////////////////// // StringStream From 79d9c71f98b0f1cfea5fae2fe33595efcbf79028 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Tue, 26 Sep 2017 16:03:09 +0800 Subject: [PATCH 04/36] fix stream wrapper initializer fix initialization warning add special wrapper for AutoUTFInputStream --- include/rapidjson/error/error.h | 4 ++-- include/rapidjson/stream.h | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index be80579..618a6cf 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -108,9 +108,9 @@ struct ParseResult { typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} + ParseResult() : code_(kParseErrorNone), offset_(0), line_(0), col_(0) {} //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset), line_(0), col_(0) {} //! Get the error code. ParseErrorCode Code() const { return code_; } diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index 4e4ba80..a315d3f 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -115,7 +115,7 @@ public: typedef typename Encoding::Ch Ch; size_t line_; size_t col_; - GenericStreamWrapper(InputStream& is): is_(is), line_(1), col_(0) {} + GenericStreamWrapper(InputStream& is): line_(1), col_(0), is_(is) {} Ch Peek() const { return is_.Peek(); } @@ -133,11 +133,17 @@ public: size_t Tell() { return is_.Tell(); } Ch* PutBegin() { return is_.PutBegin(); } - void Put(Ch ch) { return is_.Put(ch); } - void Flush() { return is_.Flush(); } - size_t PutEnd(Ch* ch) { is_.PutEnd(ch); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - const Ch* Peek4() const { is_.Peek4(); } + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + private: InputStream& is_; }; From 143641c75abaf6f111c79152b76996324ed3ad19 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Wed, 27 Sep 2017 13:58:16 +0800 Subject: [PATCH 05/36] suppress C4512, C4702 warning --- include/rapidjson/stream.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index a315d3f..556c30a 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -109,6 +109,12 @@ inline void PutN(Stream& stream, Ch c, size_t n) { \tmessage to the origin stream. \note implements Stream concept */ + +#if defined(_MSC_VER) && _MSC_VER <= 1700 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // disable unreachable code +#endif + template class GenericStreamWrapper { public: @@ -135,7 +141,7 @@ public: Ch* PutBegin() { return is_.PutBegin(); } void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } - size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } // wrapper for MemoryStream const Ch* Peek4() const { return is_.Peek4(); } @@ -146,8 +152,17 @@ public: private: InputStream& is_; + + // elimante vs2010-2013 C4512 warning by + // prohibiting copy constructor & assignment operator. + GenericStreamWrapper& operator=(const GenericStreamWrapper &); + GenericStreamWrapper(const GenericStreamWrapper&); }; +#if defined(_MSC_VER) && _MSC_VER <= 1700 +RAPIDJSON_DIAG_POP +#endif + /////////////////////////////////////////////////////////////////////////////// // StringStream From 799fdea9fc05aa74c2ebfb49340943195ac2e1dc Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Thu, 28 Sep 2017 16:57:52 +0800 Subject: [PATCH 06/36] add cursor wrapper --- include/rapidjson/cursorstreamwrapper.h | 59 +++++++++++++++++++++++++ include/rapidjson/document.h | 11 +---- include/rapidjson/error/error.h | 12 +---- include/rapidjson/stream.h | 37 +++++----------- 4 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 include/rapidjson/cursorstreamwrapper.h diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h new file mode 100644 index 0000000..5c752af --- /dev/null +++ b/include/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,59 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index de65740..93b091f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2219,17 +2219,14 @@ public: \return The document itself for fluent API. */ template - GenericDocument& ParseStream(InputStream& is_) { + GenericDocument& ParseStream(InputStream& is) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); - GenericStreamWrapper is(is_); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document - } else { - parseResult_.SetPos(is.line_, is.col_); } return *this; } @@ -2358,12 +2355,6 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorLine() const { return parseResult_.Line(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorColumn() const { return parseResult_.Col(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 618a6cf..9311d2f 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -108,18 +108,14 @@ struct ParseResult { typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0), line_(0), col_(0) {} + ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset), line_(0), col_(0) {} + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Get the position of line number if error exists. - size_t Line() const { return line_; } - //! Get the position of column number if error exists. - size_t Col() const { return col_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } @@ -138,14 +134,10 @@ public: void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - //! Update line number and column number of the error position - void SetPos(size_t line, size_t col) { line_ = line; col_ = col; } private: ParseErrorCode code_; size_t offset_; - size_t line_; - size_t col_; }; //! Function pointer type of GetParseError(). diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index 556c30a..f492797 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -104,40 +104,28 @@ inline void PutN(Stream& stream, Ch c, size_t n) { // GenericStreamWrapper //! A Stream Wrapper -/*! \tThis string stream is designed for counting line and column number - \tof the error (if exists) position, while just forwarding any received - \tmessage to the origin stream. +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. \note implements Stream concept */ -#if defined(_MSC_VER) && _MSC_VER <= 1700 +#if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // disable unreachable code +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif -template +template > class GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; size_t line_; size_t col_; - GenericStreamWrapper(InputStream& is): line_(1), col_(0), is_(is) {} + GenericStreamWrapper(InputStream& is): is_(is) {} Ch Peek() const { return is_.Peek(); } - - // counting line and column number - Ch Take() { - Ch ch = is_.Take(); - if(ch == '\n') { - line_ ++; - col_ = 0; - } else { - col_ ++; - } - return ch; - } + Ch Take() { return is_.Take(); } size_t Tell() { return is_.Tell(); } - Ch* PutBegin() { return is_.PutBegin(); } void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } @@ -150,16 +138,11 @@ public: UTFType GetType() const { return is_.GetType(); } bool HasBOM() const { return is_.HasBOM(); } -private: +protected: InputStream& is_; - - // elimante vs2010-2013 C4512 warning by - // prohibiting copy constructor & assignment operator. - GenericStreamWrapper& operator=(const GenericStreamWrapper &); - GenericStreamWrapper(const GenericStreamWrapper&); }; -#if defined(_MSC_VER) && _MSC_VER <= 1700 +#if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_POP #endif From 66541b8926c349cea4bee16630a3d38693da4588 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 17:24:07 +0800 Subject: [PATCH 07/36] add unit test for cursorstreamwrapper --- test/unittest/CMakeLists.txt | 1 + test/unittest/cursorstreamwrappertest.cpp | 115 ++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 test/unittest/cursorstreamwrappertest.cpp diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index fdf0ad0..072b7b1 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -3,6 +3,7 @@ include(CheckCXXCompilerFlag) set(UNITTEST_SOURCES allocatorstest.cpp bigintegertest.cpp + cursorstreamwrappertest.cpp documenttest.cpp dtoatest.cpp encodedstreamtest.cpp diff --git a/test/unittest/cursorstreamwrappertest.cpp b/test/unittest/cursorstreamwrappertest.cpp new file mode 100644 index 0000000..a116248 --- /dev/null +++ b/test/unittest/cursorstreamwrappertest.cpp @@ -0,0 +1,115 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "unittest.h" +#include "rapidjson/document.h" +#include "rapidjson/cursorstreamwrapper.h" + +using namespace rapidjson; + +// static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + +bool testJson(const char *json, size_t &line, size_t &col) { + StringStream ss(json); + CursorStreamWrapper csw(ss); + Document document; + document.ParseStream(csw); + bool ret = document.HasParseError(); + if (ret) { + col = csw.GetColumn(); + line = csw.GetLine(); + } + return ret; +} + +TEST(CursorStreamWrapper, MissingFirstBracket) { + const char json[] = "\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 0); +} + +TEST(CursorStreamWrapper, MissingQuotes) { + const char json[] = "{\"string\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 1); + EXPECT_EQ(col, 8); +} + +TEST(CursorStreamWrapper, MissingColon) { + const char json[] = "{\"string\"\n\n\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 0); +} + +TEST(CursorStreamWrapper, MissingSecondQuotes) { + const char json[] = "{\"string\"\n\n:my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 1); +} + +TEST(CursorStreamWrapper, MissingComma) { + const char json[] = "{\"string\"\n\n:\"my string\"\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 12); +} + +TEST(CursorStreamWrapper, MissingArrayBracket) { + const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 9); +} + +TEST(CursorStreamWrapper, MissingArrayComma) { + const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\" \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 6); +} + +TEST(CursorStreamWrapper, MissingLastArrayBracket) { + const char json8[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"}"; + size_t col, line; + bool ret = testJson(json8, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 15); +} + +TEST(CursorStreamWrapper, MissingLastBracket) { + const char json9[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]"; + size_t col, line; + bool ret = testJson(json9, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 16); +} From 9394b84440fcbf4c2db80049e46c36a78bda04b8 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 18:19:41 +0800 Subject: [PATCH 08/36] remove unnecessary code --- include/rapidjson/stream.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index f492797..7f2643e 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" @@ -104,7 +104,7 @@ inline void PutN(Stream& stream, Ch c, size_t n) { // GenericStreamWrapper //! A Stream Wrapper -/*! \tThis string stream is a wrapper for any stream by just forwarding any +/*! \tThis string stream is a wrapper for any stream by just forwarding any \treceived message to the origin stream. \note implements Stream concept */ @@ -119,10 +119,8 @@ template > class GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; - size_t line_; - size_t col_; GenericStreamWrapper(InputStream& is): is_(is) {} - + Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() { return is_.Tell(); } @@ -130,10 +128,10 @@ public: void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - + // wrapper for MemoryStream const Ch* Peek4() const { return is_.Peek4(); } - + // wrapper for AutoUTFInputStream UTFType GetType() const { return is_.GetType(); } bool HasBOM() const { return is_.HasBOM(); } From 473553bd5ae255217d4176666bff604faa464826 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 19:13:29 +0800 Subject: [PATCH 09/36] fix gcc & cl warning --- include/rapidjson/cursorstreamwrapper.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h index 5c752af..52c11a7 100644 --- a/include/rapidjson/cursorstreamwrapper.h +++ b/include/rapidjson/cursorstreamwrapper.h @@ -17,6 +17,17 @@ #include "stream.h" +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + RAPIDJSON_NAMESPACE_BEGIN @@ -29,9 +40,9 @@ class CursorStreamWrapper : public GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; - CursorStreamWrapper(InputStream& is): + CursorStreamWrapper(InputStream& is): GenericStreamWrapper(is), line_(1), col_(0) {} - + // counting line and column number Ch Take() { Ch ch = this->is_.Take(); @@ -54,6 +65,14 @@ private: size_t col_; //!< Current Column }; +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ From 84ca485e51af4fec2ab121c7ddb597dd0f7b3c76 Mon Sep 17 00:00:00 2001 From: Captain Crutches Date: Mon, 2 Oct 2017 20:39:40 -0400 Subject: [PATCH 10/36] Make RapidJSON_INCLUDE_DIR non-blank in Config.cmake --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ccc374..ac1fc25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,8 @@ EXPORT( PACKAGE ${PROJECT_NAME} ) # ... for the build tree SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}) +SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/include" ) + CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in From f0391747e608555b3f70ae6b9c902c5082e80907 Mon Sep 17 00:00:00 2001 From: David Newman Date: Tue, 3 Oct 2017 23:26:19 -0400 Subject: [PATCH 11/36] chore: correct spelling --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b833a98..78c9540 100644 --- a/readme.md +++ b/readme.md @@ -43,7 +43,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml]( More features can be read [here](doc/features.md). -JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at +JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) * [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) * [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) From 6e08e2942509389dbeec137c6079c464b92ba646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Dupuis?= Date: Thu, 5 Oct 2017 11:39:21 +0200 Subject: [PATCH 12/36] Initialized regex with schema allocator. --- include/rapidjson/schema.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index abcf1a1..d884064 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -935,7 +935,7 @@ private: }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; + typedef internal::GenericRegex RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else @@ -995,7 +995,7 @@ private: template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); From b217cc640c6afeadab23e30dbb588245a4cbfde3 Mon Sep 17 00:00:00 2001 From: piotr-kaminski-intel <32583365+piotr-kaminski-intel@users.noreply.github.com> Date: Sat, 7 Oct 2017 00:50:55 +0200 Subject: [PATCH 13/36] Removing Klocwork issues from schema.h Removing Klocwork static code analysis critical issues: line 358: 'this->notValidatorIndex_' might not be initialized in this constructor. line :412 Pointer 'schemaDocument' checked for NULL at line 412 may be passed to function and may be dereferenced there by passing argument this to function 'CreateSchema' at line 419. Also there are 7 similar errors on lines 467 479 511 523 533 538 549. --- include/rapidjson/schema.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index abcf1a1..2c5def1 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -355,6 +355,7 @@ public: not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), + notValidatorIndex_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), @@ -409,11 +410,9 @@ public: } } - if (schemaDocument) { - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - } + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); From f64b77300735c1648fc695ef5df321b693f4e14b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 9 Oct 2017 11:33:48 +0800 Subject: [PATCH 14/36] Partially fix #1077 --- include/rapidjson/encodings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index 0df1c34..7903e76 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -384,7 +384,7 @@ struct UTF16BE : UTF16 { static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())); return static_cast(c); } From 495266271fb12b6d3ed0a9cf3e251e8b240a6d87 Mon Sep 17 00:00:00 2001 From: Captain Crutches Date: Sun, 8 Oct 2017 23:43:18 -0400 Subject: [PATCH 15/36] Use SOURCE_DIR instead of CMAKE_DIR for build tree --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac1fc25..846828f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ EXPORT( PACKAGE ${PROJECT_NAME} ) # ... for the build tree SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}) -SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/include" ) +SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_SOURCE_DIR}/include" ) CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) From bb99ccb0309bb1cd5b3650af8ee6336325813040 Mon Sep 17 00:00:00 2001 From: piotr-kaminski-intel <32583365+piotr-kaminski-intel@users.noreply.github.com> Date: Tue, 10 Oct 2017 14:09:23 +0200 Subject: [PATCH 16/36] Init variable in the constructor line 358: 'this->notValidatorIndex_' might not be initialized in this constructor. --- include/rapidjson/schema.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 2c5def1..cbcb550 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -410,9 +410,11 @@ public: } } - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); From 7bd9b5a1adeb24724ae1e0f1cf048d3f3ba09d85 Mon Sep 17 00:00:00 2001 From: "M.Tayel" <32839716+m-tayel@users.noreply.github.com> Date: Mon, 16 Oct 2017 15:01:27 +0200 Subject: [PATCH 17/36] enable cross compiling by adding option to remove -march/-cpu --- CMakeLists.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 846828f..950d115 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,8 @@ option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON) option(RAPIDJSON_BUILD_ASAN "Build rapidjson with address sanitizer (gcc/clang)" OFF) option(RAPIDJSON_BUILD_UBSAN "Build rapidjson with undefined behavior sanitizer (gcc/clang)" OFF) +option(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT "Build rapidjson with -march or -mcpu options" ON) + option(RAPIDJSON_HAS_STDSTRING "" OFF) if(RAPIDJSON_HAS_STDSTRING) add_definitions(-DRAPIDJSON_HAS_STDSTRING) @@ -50,11 +52,13 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") - else() - #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + if(${RAPIDJSON_DISABLE_INSTRUMENTATION_OPT}) + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") + else() + #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion) From a8e99906039b62ababdab1e709f7e27ccccee5e0 Mon Sep 17 00:00:00 2001 From: h46incon Date: Thu, 19 Oct 2017 20:41:27 +0800 Subject: [PATCH 18/36] Add MemberCapacity() and MemberReserve() interface for object type. --- include/rapidjson/document.h | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 93b091f..094a07e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1070,6 +1070,9 @@ public: //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } @@ -1138,6 +1141,21 @@ public: /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } + //! Check whether a member exists in the object. /*! \param name Member name to be searched. @@ -1243,17 +1261,8 @@ public: RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); @@ -2548,6 +2557,7 @@ public: ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } @@ -2556,6 +2566,7 @@ public: #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } From db305dcf217ea1dd009a1355835932de6d866cb5 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 20 Oct 2017 10:33:37 +0800 Subject: [PATCH 19/36] Fix schema.md TOC --- doc/schema.md | 18 +++++++++--------- doc/schema.zh-cn.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index 29ba4f5..dc01626 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -## Basic Usage +# Basic Usage First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -## Validation during parsing/serialization +# Validation during parsing/serialization Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -### DOM parsing +## DOM parsing For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX parsing +## SAX parsing For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### Serialization +## Serialization It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -## Remote Schema +# Remote Schema JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## Conformance +# Conformance RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -### Regular Expression +## Regular Expression The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -## Performance +# Performance Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md index 5df1f31..1dd7e79 100644 --- a/doc/schema.zh-cn.md +++ b/doc/schema.zh-cn.md @@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document [TOC] -## 基本用法 +# 基本用法 首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`。 @@ -52,11 +52,11 @@ if (!d.Accept(validator)) { * 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 `SchemaValidator` 修改。 * 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`。 -## 在解析/生成时进行校验 +# 在解析/生成时进行校验 与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。 -### DOM 解析 +## DOM 解析 在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader`、`SchemaValidator` 和 `Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。 @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX 解析 +## SAX 解析 使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### 生成 +## 生成 我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。 @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { 当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。 -## 远程 Schema +# 远程 Schema JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## 标准的符合程度 +# 标准的符合程度 RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。 @@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON 除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。 -### 正则表达式 +## 正则表达式 `pattern` 及 `patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。 @@ -211,7 +211,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。 -## 性能 +# 性能 大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。 From 3c07cecdb85aa3b3a680402bc7c4a19bb942185d Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 20 Oct 2017 11:16:44 +0800 Subject: [PATCH 20/36] Add anchors to Schema.md --- doc/schema.md | 18 +++++++++--------- doc/schema.zh-cn.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index dc01626..5e396ce 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -# Basic Usage +# Basic Usage {#BasicUsage} First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -# Validation during parsing/serialization +# Validation during parsing/serialization {#ParsingSerialization} Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -## DOM parsing +## DOM parsing {#DomParsing} For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -## SAX parsing +## SAX parsing {#SaxParsing} For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -## Serialization +## Serialization {#Serialization} It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -# Remote Schema +# Remote Schema {#RemoteSchema} JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -# Conformance +# Conformance {#Conformance} RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -## Regular Expression +## Regular Expression {#RegEx} The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -# Performance +# Performance {#Performance} Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md index 1dd7e79..c85177f 100644 --- a/doc/schema.zh-cn.md +++ b/doc/schema.zh-cn.md @@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document [TOC] -# 基本用法 +# 基本用法 {#BasicUsage} 首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`。 @@ -52,11 +52,11 @@ if (!d.Accept(validator)) { * 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 `SchemaValidator` 修改。 * 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`。 -# 在解析/生成时进行校验 +# 在解析/生成时进行校验 {#ParsingSerialization} 与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。 -## DOM 解析 +## DOM 解析 {#DomParsing} 在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader`、`SchemaValidator` 和 `Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。 @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -## SAX 解析 +## SAX 解析 {#SaxParsing} 使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -## 生成 +## 生成 {#Serialization} 我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。 @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { 当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。 -# 远程 Schema +# 远程 Schema {#RemoteSchema} JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -# 标准的符合程度 +# 标准的符合程度 {#Conformance} RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。 @@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON 除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。 -## 正则表达式 +## 正则表达式 {#RegEx} `pattern` 及 `patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。 @@ -211,7 +211,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。 -# 性能 +# 性能 {#Performance} 大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。 From f4b1f761f31352348bf142095643d61e84795dc8 Mon Sep 17 00:00:00 2001 From: "M.Tayel" <32839716+m-tayel@users.noreply.github.com> Date: Tue, 24 Oct 2017 12:25:47 +0200 Subject: [PATCH 21/36] Fixed typo in CMake file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 950d115..8d69855 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(${RAPIDJSON_DISABLE_INSTRUMENTATION_OPT}) + if(${RAPIDJSON_ENABLE_INSTRUMENTATION_OPT}) if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() From 1be14d04a05fc8bcb7ad2fdb72fb7f71f50a337f Mon Sep 17 00:00:00 2001 From: clach04 Date: Thu, 26 Oct 2017 21:19:54 -0700 Subject: [PATCH 22/36] Fix issue #1104 Solaris compilation errors fread()/fwrite() Explicit std name space for fread() and fwrite(). --- include/rapidjson/filereadstream.h | 2 +- include/rapidjson/filewritestream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index b56ea13..f1bfb7d 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -68,7 +68,7 @@ private: ++current_; else if (!eof_) { count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 6378dd6..3811f8b 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -62,7 +62,7 @@ public: void Flush() { if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors From 8684c9960de4e2b028ea0f51a0d5dd8e68ff4345 Mon Sep 17 00:00:00 2001 From: Martin Lindhe Date: Sat, 4 Nov 2017 10:32:02 +0100 Subject: [PATCH 23/36] fix some typos --- CHANGELOG.md | 2 +- doc/dom.md | 2 +- doc/encoding.md | 2 +- doc/faq.md | 16 ++++++++-------- doc/performance.md | 2 +- doc/pointer.md | 2 +- doc/sax.md | 2 +- doc/schema.md | 2 +- doc/tutorial.md | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9d603c..1c580bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). * Redo all documentation (English, Simplified Chinese) ### Changed -* Copyright ownership transfered to THL A29 Limited (a Tencent company). +* Copyright ownership transferred to THL A29 Limited (a Tencent company). * Migrating from Premake to CMAKE (#192) * Resolve all warning reports diff --git a/doc/dom.md b/doc/dom.md index 6c541fe..25ffbd2 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -241,7 +241,7 @@ Some techniques about using DOM API is discussed here. ## DOM as SAX Event Publisher -In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weired. +In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weird. ~~~~~~~~~~cpp // ... diff --git a/doc/encoding.md b/doc/encoding.md index 8f8ff7f..e663aea 100644 --- a/doc/encoding.md +++ b/doc/encoding.md @@ -10,7 +10,7 @@ The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that, > (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used. -RapidJSON supports various encodings. It can also validate the encodings of JSON, and transconding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)). +RapidJSON supports various encodings. It can also validate the encodings of JSON, and transcoding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)). [TOC] diff --git a/doc/faq.md b/doc/faq.md index 74d770d..d5697ff 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -116,7 +116,7 @@ ~~~~~~~~~~cpp Value(kObjectType).Swap(d); ~~~~~~~~~~ - or equivalent, but sightly longer to type: + or equivalent, but slightly longer to type: ~~~~~~~~~~cpp d.Swap(Value(kObjectType).Move()); ~~~~~~~~~~ @@ -140,11 +140,11 @@ } ~~~~~~~~~~ - The most important requirement to take care of document and value life-cycle as well as consistent memory managent using the right allocator during the value transfer. + The most important requirement to take care of document and value life-cycle as well as consistent memory management using the right allocator during the value transfer. Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value: ~~~~~~~~~~cpp - Documnet address(person.GetAllocator()); + Document address(person.GetAllocator()); ... person["person"].AddMember("address", address["address"], person.GetAllocator()); ~~~~~~~~~~ @@ -174,7 +174,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 3. Why do I need to provide the length of string? - Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unncessary overhead of many operations, if the user already knows the length of string. + Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unnecessary overhead of many operations, if the user already knows the length of string. Also, RapidJSON can handle `\u0000` (null character) within a string. If a string contains null characters, `strlen()` cannot return the true length of it. In such case user must provide the length of string explicitly. @@ -204,7 +204,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 2. Can it validate the encoding? - Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it wil generate `kParseErrorStringInvalidEncoding` error. + Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it will generate `kParseErrorStringInvalidEncoding` error. 3. What is surrogate pair? Does RapidJSON support it? @@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 1. Is RapidJSON really fast? - Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libaries. + Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libraries. 2. Why is it fast? @@ -262,13 +262,13 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres The design of RapidJSON aims at reducing memory footprint. - In the SAX API, `Reader` consumes memory portional to maximum depth of JSON tree, plus maximum length of JSON string. + In the SAX API, `Reader` consumes memory proportional to maximum depth of JSON tree, plus maximum length of JSON string. In the DOM API, each `Value` consumes exactly 16/24 bytes for 32/64-bit architecture respectively. RapidJSON also uses a special memory allocator to minimize overhead of allocations. 5. What is the purpose of being high performance? - Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throuput. In a broad sense, it will also save energy. + Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throughput. In a broad sense, it will also save energy. ## Gossip diff --git a/doc/performance.md b/doc/performance.md index 7b18730..6f9e1bf 100644 --- a/doc/performance.md +++ b/doc/performance.md @@ -1,6 +1,6 @@ # Performance -There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libaries. +There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libraries. [1]: https://github.com/miloyip/nativejson-benchmark diff --git a/doc/pointer.md b/doc/pointer.md index b343d78..9a0e5ca 100644 --- a/doc/pointer.md +++ b/doc/pointer.md @@ -211,7 +211,7 @@ p.Stringify(sb); std::cout << sb.GetString() << std::endl; ~~~ -It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`. +It can also stringify to URI fragment representation by `StringifyUriFragment()`. # User-Supplied Tokens {#UserSuppliedTokens} diff --git a/doc/sax.md b/doc/sax.md index 4867880..874361f 100644 --- a/doc/sax.md +++ b/doc/sax.md @@ -126,7 +126,7 @@ When the `Reader` encounters a JSON number, it chooses a suitable C++ type mappi When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it. -Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. +Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArray()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing. diff --git a/doc/schema.md b/doc/schema.md index 5e396ce..b454225 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -49,7 +49,7 @@ if (!d.Accept(validator)) { Some notes: -* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. +* One `SchemaDocument` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. # Validation during parsing/serialization {#ParsingSerialization} diff --git a/doc/tutorial.md b/doc/tutorial.md index 167b81d..3fa63c9 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -68,7 +68,7 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); t = true ~~~~~~~~~~ -JSON null can be queryed with `IsNull()`. +JSON null can be queried with `IsNull()`. ~~~~~~~~~~cpp printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); ~~~~~~~~~~ From 25c1b78f3c905284d7194430f083b0381d7aff83 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:15:01 +0100 Subject: [PATCH 24/36] ignore DS_Store files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e7e8fba..1d3073f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ Doxyfile Doxyfile.zh-cn DartConfiguration.tcl *.nupkg + +# Files created by OS +*.DS_Store From 195dc90d27bf6552cab4503cc842b2d3bd3b3828 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:18:51 +0100 Subject: [PATCH 25/36] Delete .DS_Store --- bin/jsonschema/remotes/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/remotes/.DS_Store diff --git a/bin/jsonschema/remotes/.DS_Store b/bin/jsonschema/remotes/.DS_Store deleted file mode 100644 index 1d098a4103d67f2b3b336934f3d7f42b462861a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRWu5S@X7Ds|H(?0kjZAgaO%dI3btXOYNNp?e>&D;7NuZ$2PWB6c8zW+eOB z^Ks%A#p59&UhngYXh}qKG(ncZgot|5bmq<%K-M+xX_ue7{;rgMVxhmNl6SwP2P)K4 zrjz#{8T!Z7rYpnNcX53hIFz={`93>*C>7{`CI$;>GS&XK|+FoU?3O>27-Z~ zU;sH=WWF$rJ{SlFf`JbPv%iZPLM Date: Mon, 4 Dec 2017 13:19:05 +0100 Subject: [PATCH 26/36] Delete .DS_Store --- bin/jsonschema/tests/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/tests/.DS_Store diff --git a/bin/jsonschema/tests/.DS_Store b/bin/jsonschema/tests/.DS_Store deleted file mode 100644 index dae9b18efac169b4f44a57c7926495a005607a85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ8r`;3?&nz2$02NM_r*n4j=^133`F1H98qEkT$!goU2Fc<7bHBbW4X8j{x-~ zicf;xV45PL`*Z&!(u&9iZYUQUmS+3r3tMGGfpDDhDZBpTZFn8WVUc}1VB81kpAHP(0stF?-7xoF z0$3~ntcg<~A}|dqFsPa>h6Ww+l6f_83JkhvHXoWdYj!B=x8wZc>7q4|BNdLa}rlnfC~I81+?j&yFH$iwRQ10tF;CG0=JwmxEbb7!QkZ>=;as-E60zX b6nVww*sqCGpwkg|I*>mDrVEV<{I&w$e{~fm From 79d5e236739c72851d66b3d5cb671caaa6585ea1 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:19:14 +0100 Subject: [PATCH 27/36] Delete .DS_Store --- bin/jsonschema/tests/draft4/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/tests/draft4/.DS_Store diff --git a/bin/jsonschema/tests/draft4/.DS_Store b/bin/jsonschema/tests/draft4/.DS_Store deleted file mode 100644 index ef142295ea00d1d19fc3d30cc4e82dd207530825..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T^D5T4N$3SRc8x4go>L0IYo$i9Huf(orExO?vd?#YAC<2OGpmKHn+A~FM+ zFPY3tnh%;}h={j`c0;r#q6$rrrL!PnUYt5}=L;ZfjzTYVPhI=kbPI|8qDj8JqCx}h z=^1$X{)bX@53|YcakFbmKiF=rZcj9aqIv5BBrVO0ha4q-$4St!$ zB7YhZqhKHy_-738s@~OGY|8J}+4khFO=x#$BH}kn2ZH|O5rBc5BUd_U^GW*f%Z{U= TWD&cD1LGl}goFwPeu04xBO^7X From d75bb90a5dd8c5946ce7496748d1cea842aabc0f Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 12 Dec 2017 21:16:07 +0100 Subject: [PATCH 28/36] Avoid inheritance from std::iterator Instead of inheriting from the deprecated std::iterator template, define the member typedefs needed for std::iterator_traits directly. Closes #1131. --- include/rapidjson/document.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 094a07e..eb6d7dc 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -45,7 +45,7 @@ RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_N #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag +#include // std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -98,16 +98,13 @@ struct GenericMember { \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template -class GenericMemberIterator - : public std::iterator >::Type> { +class GenericMemberIterator { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; public: //! Iterator type itself @@ -117,12 +114,21 @@ public: //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; + typedef pointer Pointer; //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; + typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. From f2a28ee4720f34efae516c04eccb97e6820644b2 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 13 Dec 2017 21:53:18 +0800 Subject: [PATCH 29/36] Add archiver example A simple (de)serialization framework using DOM and SAX API --- example/CMakeLists.txt | 2 + example/archiver/archiver.cpp | 292 ++++++++++++++++++++++++++++++ example/archiver/archiver.h | 139 ++++++++++++++ example/archiver/archivertest.cpp | 281 ++++++++++++++++++++++++++++ 4 files changed, 714 insertions(+) create mode 100644 example/archiver/archiver.cpp create mode 100644 example/archiver/archiver.h create mode 100644 example/archiver/archivertest.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index e00f77a..ff54199 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -32,6 +32,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") endif() +add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp) + foreach (example ${EXAMPLES}) add_executable(${example} ${example}/${example}.cpp) endforeach() diff --git a/example/archiver/archiver.cpp b/example/archiver/archiver.cpp new file mode 100644 index 0000000..59ae4c4 --- /dev/null +++ b/example/archiver/archiver.cpp @@ -0,0 +1,292 @@ +#include "archiver.h" +#include +#include +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" + +using namespace rapidjson; + +struct JsonReaderStackItem { + enum State { + BeforeStart, //!< An object/array is in the stack but it is not yet called by StartObject()/StartArray(). + Started, //!< An object/array is called by StartObject()/StartArray(). + Closed //!< An array is closed after read all element, but before EndArray(). + }; + + JsonReaderStackItem(const Value* value, State state) : value(value), state(state), index() {} + + const Value* value; + State state; + SizeType index; // For array iteration +}; + +typedef std::stack JsonReaderStack; + +#define DOCUMENT reinterpret_cast(mDocument) +#define STACK (reinterpret_cast(mStack)) +#define TOP (STACK->top()) +#define CURRENT (*TOP.value) + +JsonReader::JsonReader(const char* json) : mDocument(), mStack(), mError(false) { + mDocument = new Document; + DOCUMENT->Parse(json); + if (DOCUMENT->HasParseError()) + mError = true; + else { + mStack = new JsonReaderStack; + STACK->push(JsonReaderStackItem(DOCUMENT, JsonReaderStackItem::BeforeStart)); + } +} + +JsonReader::~JsonReader() { + delete DOCUMENT; + delete STACK; +} + +// Archive concept +JsonReader& JsonReader::StartObject() { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::BeforeStart) + TOP.state = JsonReaderStackItem::Started; + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::EndObject() { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) + Next(); + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::Member(const char* name) { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) { + Value::ConstMemberIterator memberItr = CURRENT.FindMember(name); + if (memberItr != CURRENT.MemberEnd()) + STACK->push(JsonReaderStackItem(&memberItr->value, JsonReaderStackItem::BeforeStart)); + else + mError = true; + } + else + mError = true; + } + return *this; +} + +bool JsonReader::HasMember(const char* name) const { + if (!mError && CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) + return CURRENT.HasMember(name); + return false; +} + +JsonReader& JsonReader::StartArray(size_t* size) { + if (!mError) { + if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::BeforeStart) { + TOP.state = JsonReaderStackItem::Started; + if (size) + *size = CURRENT.Size(); + + if (!CURRENT.Empty()) { + const Value* value = &CURRENT[TOP.index]; + STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart)); + } + else + TOP.state = JsonReaderStackItem::Closed; + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::EndArray() { + if (!mError) { + if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::Closed) + Next(); + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(bool& b) { + if (!mError) { + if (CURRENT.IsBool()) { + b = CURRENT.GetBool(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(unsigned& u) { + if (!mError) { + if (CURRENT.IsUint()) { + u = CURRENT.GetUint(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(int& i) { + if (!mError) { + if (CURRENT.IsInt()) { + i = CURRENT.GetInt(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(double& d) { + if (!mError) { + if (CURRENT.IsNumber()) { + d = CURRENT.GetDouble(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(std::string& s) { + if (!mError) { + if (CURRENT.IsString()) { + s = CURRENT.GetString(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::SetNull() { + // This function is for JsonWriter only. + mError = true; + return *this; +} + +void JsonReader::Next() { + if (!mError) { + assert(!STACK->empty()); + STACK->pop(); + + if (!STACK->empty() && CURRENT.IsArray()) { + if (TOP.state == JsonReaderStackItem::Started) { // Otherwise means reading array item pass end + if (TOP.index < CURRENT.Size() - 1) { + const Value* value = &CURRENT[++TOP.index]; + STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart)); + } + else + TOP.state = JsonReaderStackItem::Closed; + } + else + mError = true; + } + } +} + +#undef DOCUMENT +#undef STACK +#undef TOP +#undef CURRENT + +//////////////////////////////////////////////////////////////////////////////// +// JsonWriter + +#define WRITER reinterpret_cast*>(mWriter) +#define STREAM reinterpret_cast(mStream) + +JsonWriter::JsonWriter() : mWriter(), mStream() { + mStream = new StringBuffer; + mWriter = new PrettyWriter(*STREAM); +} + +JsonWriter::~JsonWriter() { + delete WRITER; + delete STREAM; +} + +const char* JsonWriter::GetString() const { + return STREAM->GetString(); +} + +JsonWriter& JsonWriter::StartObject() { + WRITER->StartObject(); + return *this; +} + +JsonWriter& JsonWriter::EndObject() { + WRITER->EndObject(); + return *this; +} + +JsonWriter& JsonWriter::Member(const char* name) { + WRITER->String(name, static_cast(strlen(name))); + return *this; +} + +bool JsonWriter::HasMember(const char*) const { + // This function is for JsonReader only. + assert(false); + return false; +} + +JsonWriter& JsonWriter::StartArray(size_t*) { + WRITER->StartArray(); + return *this; +} + +JsonWriter& JsonWriter::EndArray() { + WRITER->EndArray(); + return *this; +} + +JsonWriter& JsonWriter::operator&(bool& b) { + WRITER->Bool(b); + return *this; +} + +JsonWriter& JsonWriter::operator&(unsigned& u) { + WRITER->Uint(u); + return *this; +} + +JsonWriter& JsonWriter::operator&(int& i) { + WRITER->Int(i); + return *this; +} + +JsonWriter& JsonWriter::operator&(double& d) { + WRITER->Double(d); + return *this; +} + +JsonWriter& JsonWriter::operator&(std::string& s) { + WRITER->String(s.c_str(), static_cast(s.size())); + return *this; +} + +JsonWriter& JsonWriter::SetNull() { + WRITER->Null(); + return *this; +} + +#undef STREAM +#undef WRITER diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h new file mode 100644 index 0000000..c7e74f0 --- /dev/null +++ b/example/archiver/archiver.h @@ -0,0 +1,139 @@ +#ifndef ARCHIVER_H_ +#define ARCHIVER_H_ + +#include +#include + +/** +\class Archiver +\brief Archiver concept + +Archiver can be a reader or writer for serialization or deserialization respectively. + +class Archiver { +public: + /// \returns true if the archiver is in normal state. false if it has errors. + operator bool() const; + + /// Starts an object + Archiver& StartObject(); + + /// After calling StartObject(), assign a member with a name + Archiver& Member(const char* name); + + /// After calling StartObject(), check if a member presents + bool HasMember(const char* name) const; + + /// Ends an object + Archiver& EndObject(); + + /// Starts an array + /// \param size If Archiver::IsReader is true, the size of array is written. + Archiver& StartArray(size_t* size = 0); + + /// Ends an array + Archiver& EndArray(); + + /// Read/Write primitive types. + Archiver& operator&(bool& b); + Archiver& operator&(unsigned& u); + Archiver& operator&(int& i); + Archiver& operator&(double& d); + Archiver& operator&(std::string& s); + + /// Write primitive types. + Archiver& SetNull(); + + //! Whether it is a reader. + static const bool IsReader; + + //! Whether it is a writer. + static const bool IsWriter; +}; +*/ + +/// Represents a JSON reader which implements Archiver concept. +class JsonReader { +public: + /// Constructor. + /** + \param json A non-const source json string for in-situ parsing. + \note in-situ means the source JSON string will be modified after parsing. + */ + JsonReader(const char* json); + + /// Destructor. + ~JsonReader(); + + // Archive concept + + operator bool() const { return !mError; } + + JsonReader& StartObject(); + JsonReader& Member(const char* name); + bool HasMember(const char* name) const; + JsonReader& EndObject(); + + JsonReader& StartArray(size_t* size = nullptr); + JsonReader& EndArray(); + + JsonReader& operator&(bool& b); + JsonReader& operator&(unsigned& u); + JsonReader& operator&(int& i); + JsonReader& operator&(double& d); + JsonReader& operator&(std::string& s); + + JsonReader& SetNull(); + + static const bool IsReader = true; + static const bool IsWriter = !IsReader; + +private: + void Next(); + + // PIMPL + void* mDocument; ///< DOM result of parsing. + void* mStack; ///< Stack for iterating the DOM + bool mError; ///< Whether an error is occured. +}; + +class JsonWriter { +public: + /// Constructor. + JsonWriter(); + + /// Destructor. + ~JsonWriter(); + + /// Obtains the serialized JSON string. + const char* GetString() const; + + // Archive concept + + operator bool() const { return true; } + + JsonWriter& StartObject(); + JsonWriter& Member(const char* name); + bool HasMember(const char* name) const; + JsonWriter& EndObject(); + + JsonWriter& StartArray(size_t* size = 0); + JsonWriter& EndArray(); + + JsonWriter& operator&(bool& b); + JsonWriter& operator&(unsigned& u); + JsonWriter& operator&(int& i); + JsonWriter& operator&(double& d); + JsonWriter& operator&(std::string& s); + JsonWriter& SetNull(); + + static const bool IsReader = false; + static const bool IsWriter = !IsReader; + +private: + // PIMPL idiom + void* mWriter; ///< JSON writer. + void* mStream; ///< Stream buffer. +}; + +#endif // ARCHIVER_H__ diff --git a/example/archiver/archivertest.cpp b/example/archiver/archivertest.cpp new file mode 100644 index 0000000..788db36 --- /dev/null +++ b/example/archiver/archivertest.cpp @@ -0,0 +1,281 @@ +#include "archiver.h" +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// Test1: simple object + +struct Student { + std::string name; + unsigned age; + double height; + bool canSwim; +}; + +template +Archiver& operator&(Archiver& ar, Student& s) { + ar.StartObject(); + ar.Member("name") & s.name; + ar.Member("age") & s.age; + ar.Member("height") & s.height; + ar.Member("canSwim") & s.canSwim; + return ar.EndObject(); +} + +std::ostream& operator<<(std::ostream& os, const Student& s) { + return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim; +} + +void test1() { + std::string json; + + // Serialize + { + Student s = { "Lua", 9, 150.5, true }; + + JsonWriter writer; + writer & s; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Student s; + JsonReader reader(json.c_str()); + reader & s; + std::cout << s << std::endl; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Test2: std::vector <=> JSON array +// +// You can map a JSON array to other data structures as well + +struct Group { + std::string groupName; + std::vector students; +}; + +template +Archiver& operator&(Archiver& ar, Group& g) { + ar.StartObject(); + + ar.Member("groupName"); + ar & g.groupName; + + ar.Member("students"); + size_t studentCount = g.students.size(); + ar.StartArray(&studentCount); + if (ar.IsReader) + g.students.resize(studentCount); + for (size_t i = 0; i < studentCount; i++) + ar & g.students[i]; + ar.EndArray(); + + return ar.EndObject(); +} + +std::ostream& operator<<(std::ostream& os, const Group& g) { + os << g.groupName << std::endl; + for (std::vector::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr) + os << *itr << std::endl; + return os; +} + +void test2() { + std::string json; + + // Serialize + { + Group g; + g.groupName = "Rainbow"; + + Student s1 = { "Lua", 9, 150.5, true }; + Student s2 = { "Mio", 7, 120.0, false }; + g.students.push_back(s1); + g.students.push_back(s2); + + JsonWriter writer; + writer & g; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Group g; + JsonReader reader(json.c_str()); + reader & g; + std::cout << g << std::endl; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Test3: polymorphism & friend +// +// Note that friendship is not necessary but make things simpler. + +class Shape { +public: + virtual ~Shape() {} + virtual const char* GetType() const = 0; + virtual void Print(std::ostream& os) const = 0; + +protected: + Shape() {} + Shape(double x, double y) : x_(x), y_(y) {} + + template + friend Archiver& operator&(Archiver& ar, Shape& s); + + double x_, y_; +}; + +template +Archiver& operator&(Archiver& ar, Shape& s) { + ar.Member("x") & s.x_; + ar.Member("y") & s.y_; + return ar; +} + +class Circle : public Shape { +public: + Circle() {} + Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {} + ~Circle() {} + + const char* GetType() const { return "Circle"; } + + void Print(std::ostream& os) const { + os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_; + } + +private: + template + friend Archiver& operator&(Archiver& ar, Circle& c); + + double radius_; +}; + +template +Archiver& operator&(Archiver& ar, Circle& c) { + ar & static_cast(c); + ar.Member("radius") & c.radius_; + return ar; +} + +class Box : public Shape { +public: + Box() {} + Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {} + ~Box() {} + + const char* GetType() const { return "Box"; } + + void Print(std::ostream& os) const { + os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_; + } + +private: + template + friend Archiver& operator&(Archiver& ar, Box& b); + + double width_, height_; +}; + +template +Archiver& operator&(Archiver& ar, Box& b) { + ar & static_cast(b); + ar.Member("width") & b.width_; + ar.Member("height") & b.height_; + return ar; +} + +class Canvas { +public: + Canvas() {} + ~Canvas() { Clear(); } + + void Clear() { + for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) + delete *itr; + } + + void AddShape(Shape* shape) { shapes_.push_back(shape); } + + void Print(std::ostream& os) { + for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) { + (*itr)->Print(os); + std::cout << std::endl; + } + } + +private: + template + friend Archiver& operator&(Archiver& ar, Canvas& c); + + std::vector shapes_; +}; + +template +Archiver& operator&(Archiver& ar, Shape*& shape) { + std::string type = ar.IsReader ? "" : shape->GetType(); + ar.StartObject(); + ar.Member("type") & type; + if (type == "Circle") { + if (ar.IsReader) shape = new Circle; + ar & static_cast(*shape); + } + else if (type == "Box") { + if (ar.IsReader) shape = new Box; + ar & static_cast(*shape); + } + return ar.EndObject(); +} + +template +Archiver& operator&(Archiver& ar, Canvas& c) { + size_t shapeCount = c.shapes_.size(); + ar.StartArray(&shapeCount); + if (ar.IsReader) { + c.Clear(); + c.shapes_.resize(shapeCount); + } + for (size_t i = 0; i < shapeCount; i++) + ar & c.shapes_[i]; + return ar.EndArray(); +} + +void test3() { + std::string json; + + // Serialize + { + Canvas c; + c.AddShape(new Circle(1.0, 2.0, 3.0)); + c.AddShape(new Box(4.0, 5.0, 6.0, 7.0)); + + JsonWriter writer; + writer & c; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Canvas c; + JsonReader reader(json.c_str()); + reader & c; + c.Print(std::cout); + } +} + +////////////////////////////////////////////////////////////////////////////// + +int main() { + test1(); + test2(); + test3(); +} From 9bfa0bb567fd16f0fe7ea615e4b8139e8e64ce73 Mon Sep 17 00:00:00 2001 From: sjaques Date: Thu, 21 Dec 2017 13:40:28 +0100 Subject: [PATCH 30/36] Fix uninitilized member Reader::state_ --- include/rapidjson/reader.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 120c311..681dec2 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -544,7 +544,8 @@ public: /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. From 20d44d9c443290bc77e720bd65850a401fd7e9f4 Mon Sep 17 00:00:00 2001 From: Lele Gaifax Date: Fri, 22 Dec 2017 19:24:15 +0100 Subject: [PATCH 31/36] Fix FileWriteStream doc --- include/rapidjson/filewritestream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 3811f8b..8b48fee 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_NAMESPACE_BEGIN -//! Wrapper of C file stream for input using fread(). +//! Wrapper of C file stream for output using fwrite(). /*! \note implements Stream concept */ From 53eadd218d705bd2dd5354eae46dd20e01dcd4e9 Mon Sep 17 00:00:00 2001 From: Haffon <31226194+Haffon@users.noreply.github.com> Date: Thu, 28 Dec 2017 16:31:26 +0800 Subject: [PATCH 32/36] GetParseOffset to GetErrorOffset --- doc/dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dom.md b/doc/dom.md index 25ffbd2..0079b64 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -128,7 +128,7 @@ And the `InputStream` is type of input stream. ## Parse Error {#ParseError} -When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`. +When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetErrorOffset()`. Parse Error Code | Description --------------------------------------------|--------------------------------------------------- From 7dfeee862d3b47df7816a5b771a6523a61b62991 Mon Sep 17 00:00:00 2001 From: Haffon <31226194+Haffon@users.noreply.github.com> Date: Thu, 28 Dec 2017 16:32:26 +0800 Subject: [PATCH 33/36] GetParseOffset to GetErrorOffset --- doc/dom.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index b709485..9743b7a 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -128,7 +128,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); ## 解析错误 {#ParseError} -当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetParseOffset()` 获取解析的错误状态。 +当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetErrorOffset()` 获取解析的错误状态。 解析错误代号 | 描述 --------------------------------------------|--------------------------------------------------- From b8c12c9ccd3602eb50696a4e0ac2249f98937059 Mon Sep 17 00:00:00 2001 From: xiaoPierre Date: Thu, 11 Jan 2018 17:45:35 +0100 Subject: [PATCH 34/36] Bug when switching to std regex I could not switch to std regex after defining the two variables as in documents. Then I try to fix it in schema.h. --- 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 2713fb2..7493871 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -25,7 +25,7 @@ #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 From 0d95d58f8b6259e06e391ce962ec2062260bcdb8 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Jan 2018 12:37:01 +0800 Subject: [PATCH 35/36] Try to fix travis build --- test/unittest/namespacetest.cpp | 4 ++++ test/unittest/unittest.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp index 1814724..9f5c9af 100644 --- a/test/unittest/namespacetest.cpp +++ b/test/unittest/namespacetest.cpp @@ -12,6 +12,10 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. +// Not throwing exception for this test +#include +#define RAPIDJSON_ASSERT(x) assert(x) + #include "unittest.h" // test another instantiation of RapidJSON in a different namespace diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index aa091aa..4b1c293 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -117,7 +117,9 @@ public: #pragma GCC diagnostic pop #endif +#ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) +#endif class Random { public: From d48290e387932ba016fb1d0117ac4b71edda45ae Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Jan 2018 12:51:24 +0800 Subject: [PATCH 36/36] Another try to fix travis build --- test/unittest/namespacetest.cpp | 4 ---- test/unittest/unittest.h | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp index 9f5c9af..1814724 100644 --- a/test/unittest/namespacetest.cpp +++ b/test/unittest/namespacetest.cpp @@ -12,10 +12,6 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -// Not throwing exception for this test -#include -#define RAPIDJSON_ASSERT(x) assert(x) - #include "unittest.h" // test another instantiation of RapidJSON in a different namespace diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 4b1c293..84c1b73 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -117,6 +117,9 @@ public: #pragma GCC diagnostic pop #endif +// Not using noexcept for testing RAPIDJSON_ASSERT() +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 + #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) #endif