From adb7d17eff3d58dfc27a84d644a73d8e93703831 Mon Sep 17 00:00:00 2001 From: miloyip Date: Sat, 18 Apr 2015 20:30:40 +0800 Subject: [PATCH 01/98] Fix warnings for misctest --- test/perftest/misctest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index 3edadda..6b276e4 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -768,7 +768,7 @@ template void itoa_Writer_StringBufferVerify() { rapidjson::StringBuffer sb; Writer writer(sb); - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; sprintf(buffer, "%d", randval[j]); writer.WriteInt(randval[j]); @@ -780,7 +780,7 @@ void itoa_Writer_StringBufferVerify() { template void itoa_Writer_InsituStringStreamVerify() { Writer writer; - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; sprintf(buffer, "%d", randval[j]); char buffer2[32]; From f7a64c5eae3a03930aad8f5ba855647e060dc10f Mon Sep 17 00:00:00 2001 From: miloyip Date: Sat, 18 Apr 2015 21:31:25 +0800 Subject: [PATCH 02/98] Add RAPIDJSON_LIKELY/UNLIKELY and apply them in stack --- include/rapidjson/internal/stack.h | 2 +- include/rapidjson/rapidjson.h | 29 +++++++++++++++++++++++++++++ test/perftest/rapidjsontest.cpp | 6 ++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 2f2c76a..b256eb9 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -98,7 +98,7 @@ public: template RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { // Expand the stack if needed - if (stackTop_ + sizeof(T) * count >= stackEnd_) + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count >= stackEnd_)) Expand(count); T* ret = reinterpret_cast(stackTop_); diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 602dabd..0efe33f 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -343,6 +343,35 @@ RAPIDJSON_NAMESPACE_END RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) x +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) x +#endif +#endif + /////////////////////////////////////////////////////////////////////////////// // Helpers diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 875c5eb..6a0fe43 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -346,4 +346,10 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { } } +TEST_F(RapidJson, StringBuffer) { + StringBuffer sb; + for (int i = 0; i < 32 * 1024 * 1024; i++) + sb.Put(i & 0x7f); +} + #endif // TEST_RAPIDJSON From 311b48224ff02466a0464d51db2ed0a3a0d6cc3b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 1 Sep 2015 10:05:33 +0800 Subject: [PATCH 03/98] Try to fix incorrect 64-bit alignment Added unit tests for alignment macros. Fixes #418 --- include/rapidjson/rapidjson.h | 6 +++--- test/unittest/allocatorstest.cpp | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index b0dabc7..4c4d983 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -238,13 +238,13 @@ \param x pointer to align Some machines require strict data alignment. Currently the default uses 4 bytes - alignment. User can customize by defining the RAPIDJSON_ALIGN function macro., + alignment. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN #if RAPIDJSON_64BIT == 1 -#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u) +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #else -#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) #endif #endif diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp index 7b4deed..792a88e 100644 --- a/test/unittest/allocatorstest.cpp +++ b/test/unittest/allocatorstest.cpp @@ -61,3 +61,23 @@ TEST(Allocator, MemoryPoolAllocator) { EXPECT_LE(a.Size(), a.Capacity()); } } + +TEST(Allocator, Alignment) { +#if RAPIDJSON_64BIT == 1 + EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0)); + for (uint64_t i = 1; i < 8; i++) { + EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i)); + EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i)); + EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i)); + EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i)); + } +#else + EXPECT_EQ(0u, RAPIDJSON_ALIGN(0u)); + for (uint32_t i = 1; i < 4; i++) { + EXPECT_EQ(4u, RAPIDJSON_ALIGN(i)); + EXPECT_EQ(8u, RAPIDJSON_ALIGN(4u + i)); + EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF4u + i)); + EXPECT_EQ(0xFFFFFFFCu, RAPIDJSON_ALIGN(0xFFFFFFF8u + i)); + } +#endif +} From 2a267ff15abea98dd63e988999bdfb8f09a85893 Mon Sep 17 00:00:00 2001 From: Kurt Johnson Date: Wed, 2 Sep 2015 09:29:15 -0500 Subject: [PATCH 04/98] check return of fwrite to avoid warn_unused_result build failures --- include/rapidjson/filewritestream.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 31223b8..55da265 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -57,7 +57,11 @@ public: void Flush() { if (current_ != buffer_) { - fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = 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 + } current_ = buffer_; } } From 8604ba0f1cfc1f2cd73a9d98085143614e587888 Mon Sep 17 00:00:00 2001 From: Rodion Malinovsky Date: Wed, 16 Sep 2015 14:53:12 +0300 Subject: [PATCH 05/98] Add asserts to prevent UB --- include/rapidjson/document.h | 5 ++++- include/rapidjson/internal/stack.h | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f5c1be9..6275f96 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1989,7 +1989,10 @@ public: //!@} //! Get the allocator of this document. - Allocator& GetAllocator() { return *allocator_; } + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 0d4a7f7..4b98e38 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -134,7 +134,10 @@ public: template T* Bottom() { return (T*)stack_; } - Allocator& GetAllocator() { return *allocator_; } + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } From c7433dfc5ede497126ca347af93ce8587beeafb0 Mon Sep 17 00:00:00 2001 From: Rodion Malinovsky Date: Wed, 16 Sep 2015 14:53:51 +0300 Subject: [PATCH 06/98] Add stack::HasAllocator To check is it possible to expose allocator. --- include/rapidjson/internal/stack.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 4b98e38..82f23dd 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -134,6 +134,10 @@ public: template T* Bottom() { return (T*)stack_; } + bool HasAllocator() const { + return allocator_ != 0; + } + Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; From 2e11498943153e72afe0af0f64aecf090c0df659 Mon Sep 17 00:00:00 2001 From: Rodion Malinovsky Date: Wed, 16 Sep 2015 14:54:38 +0300 Subject: [PATCH 07/98] Fix the usage of the stack::GetAllocator --- include/rapidjson/document.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 6275f96..0a5a7b2 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1887,7 +1887,8 @@ public: template GenericDocument& ParseStream(InputStream& is) { ValueType::SetNull(); // Remove existing root if exist - GenericReader reader(&stack_.GetAllocator()); + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { From fa123699d32948eb4f539934a4574e3b73ce6c3d Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 7 Oct 2015 21:48:39 +0200 Subject: [PATCH 08/98] Keep Document value unchanged on parse error, fixes #437 Keeping the DOM unchanged in case of an error is the intended behaviour according to the [documentation] [1]. Instead of forcing the value to `kNullType` before starting the parsing, store the parsed value upon success via regular move. [1]: https://miloyip.github.io/rapidjson/md_doc_dom.html#ParseError --- include/rapidjson/document.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 0a5a7b2..516cb5e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1886,14 +1886,13 @@ public: */ template GenericDocument& ParseStream(InputStream& is) { - ValueType::SetNull(); // Remove existing root if exist GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } From 41dd68f092d9a90e8cf87ba78a4af7dbccf261d9 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 7 Oct 2015 21:50:14 +0200 Subject: [PATCH 09/98] add simple test for unchanged DOM after parse error --- test/unittest/documenttest.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 810a99c..83325a7 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -95,6 +95,21 @@ TEST(Document, Parse) { ParseTest(); } +TEST(Document, UnchangedOnParseError) { + Document doc; + doc.SetArray().PushBack(0, doc.GetAllocator()); + + doc.Parse("{]"); + EXPECT_TRUE(doc.HasParseError()); + EXPECT_TRUE(doc.IsArray()); + EXPECT_EQ(doc.Size(), 1u); + + doc.Parse("{}"); + EXPECT_FALSE(doc.HasParseError()); + EXPECT_TRUE(doc.IsObject()); + EXPECT_EQ(doc.MemberCount(), 0u); +} + static FILE* OpenEncodedFile(const char* filename) { const char *paths[] = { "encodings/%s", From 481ae5b11d72d56d43eed809d37ddafc45cf609f Mon Sep 17 00:00:00 2001 From: Sean Leather Date: Fri, 9 Oct 2015 14:29:30 +0200 Subject: [PATCH 10/98] Highlight main features in bold Might help some people see things better when skimming. --- readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 8682df1..fb270fb 100644 --- a/readme.md +++ b/readme.md @@ -31,15 +31,15 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/). -* RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. +* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. -* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. +* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. -* RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL. +* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL. -* RapidJSON is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. +* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. -* RapidJSON is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). +* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). More features can be read [here](doc/features.md). From 1640ce613ca3bd3b9602c0f9e491c016137f5717 Mon Sep 17 00:00:00 2001 From: FrankHB Date: Sat, 10 Oct 2015 11:33:48 +0800 Subject: [PATCH 11/98] Fixed typo should be . --- include/rapidjson/internal/swap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/internal/swap.h b/include/rapidjson/internal/swap.h index 41e7e20..39bc2e4 100644 --- a/include/rapidjson/internal/swap.h +++ b/include/rapidjson/internal/swap.h @@ -20,7 +20,7 @@ RAPIDJSON_NAMESPACE_BEGIN namespace internal { -//! Custom swap() to avoid dependency on C++ header +//! Custom swap() to avoid dependency on C++ header /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. \note This has the same semantics as std::swap(). */ From 5ce78b135d7fd76589973607b707dd7dbcab0792 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sun, 11 Oct 2015 15:01:15 +0300 Subject: [PATCH 12/98] Introduce support of comments. --- include/rapidjson/reader.h | 48 ++++++++++++++++++------- test/unittest/readertest.cpp | 70 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 9a17301..2603992 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -140,6 +140,7 @@ enum ParseFlag { kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; @@ -398,7 +399,7 @@ public: ClearStackOnExit scope(*this); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); if (is.Peek() == '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); @@ -409,7 +410,7 @@ public: RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespace(is); + SkipWhitespaceAndComments(is); if (is.Peek() != '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); @@ -462,6 +463,29 @@ private: ClearStackOnExit& operator=(const ClearStackOnExit&); }; + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (is.Peek() == '/') { + is.Take(); + + if (is.Peek() == '*') { + is.Take(); + while (is.Take() != '*' || is.Take() != '/') { } + } else if (is.Peek() == '/') { + is.Take(); + while (is.Take() != '\n') { } + } else { + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + } + + SkipWhitespace(is); + } + } + } + // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { @@ -471,7 +495,7 @@ private: if (!handler.StartObject()) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); if (is.Peek() == '}') { is.Take(); @@ -487,22 +511,22 @@ private: ParseString(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); if (is.Take() != ':') RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); ++memberCount; switch (is.Take()) { - case ',': SkipWhitespace(is); break; + case ',': SkipWhitespaceAndComments(is); break; case '}': if (!handler.EndObject(memberCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); @@ -521,7 +545,7 @@ private: if (!handler.StartArray()) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); if (is.Peek() == ']') { is.Take(); @@ -535,10 +559,10 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); switch (is.Take()) { - case ',': SkipWhitespace(is); break; + case ',': SkipWhitespaceAndComments(is); break; case ']': if (!handler.EndArray(elementCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); @@ -1404,7 +1428,7 @@ private: ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); @@ -1421,7 +1445,7 @@ private: if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); } // Handle the end of file. diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 9106063..010a1a9 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1349,6 +1349,76 @@ TEST(Reader, ParseTerminationByHandler) { TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array } +TEST(Reader, ParseComments) { + const char* json = + "// Here is a one-line comment.\n" + "{// And here's another one\n" + " /*And here's an in-line one.*/\"hello\" : \"world\"," + " \"t\" :/* And one with '*' symbol*/true ," + "/* A multiline comment\n" + " goes here*/" + " \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]" + "}/*And the last one to be sure */"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(20u, h.step_); +} + +TEST(Reader, ParseEmptyInlineComment) { + const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(20u, h.step_); +} + +TEST(Reader, ParseEmptyOnelineComment) { + const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(20u, h.step_); +} + +TEST(Reader, InlineCommentsAreDisabledByDefault) { + { + const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_FALSE(reader.Parse(s, h)); + } + + { + const char* json = + "{\"hello\" : /* Multiline comment starts here\n" + " continues here\n" + " and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_FALSE(reader.Parse(s, h)); + } +} + +TEST(Reader, OnelineCommentsAreDisabledByDefault) { + const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_FALSE(reader.Parse(s, h)); +} + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif From f7960ac0e8740f81980e8cd11284cac54f9f44be Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Oct 2015 23:57:54 +0300 Subject: [PATCH 13/98] Comments parsing fixes. * Comments parsing function correctly handles EOF. * Since SkipWhitespaceAndComments can generate errors, its calls should be followed by RAPIDJSON_PARSE_ERROR_EARLY_RETURN macro. * Some tests to make the bug never appear again. --- include/rapidjson/reader.h | 35 +++++++++++++++++++++++++++++++---- test/unittest/readertest.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 2603992..fba9f19 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -400,6 +400,7 @@ public: ClearStackOnExit scope(*this); SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (is.Peek() == '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); @@ -411,6 +412,7 @@ public: if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (is.Peek() != '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); @@ -473,10 +475,21 @@ private: if (is.Peek() == '*') { is.Take(); - while (is.Take() != '*' || is.Take() != '/') { } + while (true) { + if (is.Peek() == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + if (is.Take() == '*') { + if (is.Peek() == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + if (is.Take() == '/') + break; + } + } } else if (is.Peek() == '/') { is.Take(); - while (is.Take() != '\n') { } + while (is.Peek() != '\0' && is.Take() != '\n') { } } else { RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); } @@ -496,6 +509,7 @@ private: RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (is.Peek() == '}') { is.Take(); @@ -512,21 +526,27 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (is.Take() != ':') RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; switch (is.Take()) { - case ',': SkipWhitespaceAndComments(is); break; + case ',': + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; case '}': if (!handler.EndObject(memberCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); @@ -546,6 +566,7 @@ private: RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (is.Peek() == ']') { is.Take(); @@ -560,9 +581,13 @@ private: ++elementCount; SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; switch (is.Take()) { - case ',': SkipWhitespaceAndComments(is); break; + case ',': + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; case ']': if (!handler.EndArray(elementCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); @@ -1429,6 +1454,7 @@ private: IterativeParsingState state = IterativeParsingStartState; SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); @@ -1446,6 +1472,7 @@ private: break; SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } // Handle the end of file. diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 010a1a9..71d7113 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1387,6 +1387,19 @@ TEST(Reader, ParseEmptyOnelineComment) { EXPECT_EQ(20u, h.step_); } +TEST(Reader, ParseMultipleCommentsInARow) { + const char* json = + "{/* first comment *//* second */\n" + "/* third */ /*fourth*/// last one\n" + "\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(20u, h.step_); +} + TEST(Reader, InlineCommentsAreDisabledByDefault) { { const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; @@ -1419,6 +1432,26 @@ TEST(Reader, OnelineCommentsAreDisabledByDefault) { EXPECT_FALSE(reader.Parse(s, h)); } +TEST(Reader, EofAfterOneLineComment) { + const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_FALSE(reader.Parse(s, h)); + EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode()); +} + +TEST(Reader, IncompleteMultilineComment) { + const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}"; + + StringStream s(json); + ParseObjectHandler h; + Reader reader; + EXPECT_FALSE(reader.Parse(s, h)); + EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode()); +} + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif From 74a021346d3a97cd112fa528c09ff8823d36145c Mon Sep 17 00:00:00 2001 From: etiennebatise Date: Wed, 14 Oct 2015 15:46:26 +0200 Subject: [PATCH 14/98] Add break at default switch case statements fix issue #444 --- include/rapidjson/document.h | 1 + include/rapidjson/reader.h | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 516cb5e..8da86ab 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2101,6 +2101,7 @@ GenericValue::GenericValue(const GenericValue(&rhs.data_); + break; } } diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index fba9f19..b56f3b5 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -551,7 +551,9 @@ private: if (!handler.EndObject(memberCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + break; } } } @@ -592,7 +594,9 @@ private: if (!handler.EndArray(elementCount)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + default: + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + break; } } } @@ -1041,7 +1045,10 @@ private: case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; - default : ParseNumber(is, handler); + default : + ParseNumber(is, handler); + break; + } } @@ -1443,7 +1450,7 @@ private: case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; } } From edd077f4bff042576736847f049cee9893930b7f Mon Sep 17 00:00:00 2001 From: etiennebatise Date: Thu, 15 Oct 2015 10:11:42 +0200 Subject: [PATCH 15/98] Add missing return statement, fix #448 --- include/rapidjson/encodedstream.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/encodedstream.h b/include/rapidjson/encodedstream.h index 7bc6ad3..13fcb1b 100644 --- a/include/rapidjson/encodedstream.h +++ b/include/rapidjson/encodedstream.h @@ -77,8 +77,8 @@ public: void Flush() { os_.Flush(); } // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } @@ -227,8 +227,8 @@ public: void Flush() { os_->Flush(); } // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } From 76d729e9c0246bc55c42e1e7ea28412772427633 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 22 Oct 2015 10:58:58 +0800 Subject: [PATCH 16/98] Add kParseCommentsFlag documentation --- doc/dom.md | 1 + doc/dom.zh-cn.md | 1 + doc/features.md | 2 ++ doc/features.zh-cn.md | 2 ++ 4 files changed, 6 insertions(+) diff --git a/doc/dom.md b/doc/dom.md index 24f1a39..cb25fc4 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -115,6 +115,7 @@ Parse flags | Meaning `kParseIterativeFlag` | Iterative(constant complexity in terms of function call stack size) parsing. `kParseStopWhenDoneFlag` | After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate `kParseErrorDocumentRootNotSingular` error. Using this flag for parsing multiple JSONs in the same stream. `kParseFullPrecisionFlag` | Parse number in full precision (slower). If this flag is not set, the normal precision (faster) is used. Normal precision has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error. +`kParseCommentsFlag` | Allow one-line `// ...` and multi-line `/* ... */` comments (relaxed JSON syntax). By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time. diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index bb4eafb..2adf343 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -115,6 +115,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); `kParseIterativeFlag` | 迭代式(调用堆栈大小为常数复杂度)解析。 `kParseStopWhenDoneFlag` | 当从流解析了一个完整的JSON根节点之后,停止继续处理余下的流。当使用了此标志,解析器便不会产生`kParseErrorDocumentRootNotSingular`错误。可使用本标志去解析同一个流里的多个JSON。 `kParseFullPrecisionFlag` | 使用完整的精确度去解析数字(较慢)。如不设置此标节,则会使用正常的精确度(较快)。正常精确度会有最多3个[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place)的误差。 +`kParseCommentsFlag` | 容许单行 `// ...` 及多行 `/* ... */` 注释(放宽的JSON语法)。 由于使用了非类型模板参数,而不是函数参数,C++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。 diff --git a/doc/features.md b/doc/features.md index fc54cd0..6b529a7 100644 --- a/doc/features.md +++ b/doc/features.md @@ -23,6 +23,8 @@ * Support Unicode surrogate. * Support null character (`"\u0000"`) * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string. +* Support optional relaxed syntax. + * Single line (`// ...`) and multiple line (`/* ... */`) comments. ## Unicode diff --git a/doc/features.zh-cn.md b/doc/features.zh-cn.md index 3a01a4b..85a7db1 100644 --- a/doc/features.zh-cn.md +++ b/doc/features.zh-cn.md @@ -23,6 +23,8 @@ * 支持Unicod代理对(surrogate pair)。 * 支持空字符(`"\u0000"`)。 * 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。 +* 支持放宽的可选语法 + * 单行(`// ...`)及多行(`/* ... */`) 注释。 ## Unicode From d5d17b96c2148f68a0c25c74ce63698d46928e3e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 27 Oct 2015 11:09:57 -0700 Subject: [PATCH 17/98] Chinese Translation of JSON Pointer guide and minor English version modification. --- doc/pointer.md | 6 +- doc/pointer.zh-cn.md | 234 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 doc/pointer.zh-cn.md diff --git a/doc/pointer.md b/doc/pointer.md index 1d75080..3927a12 100644 --- a/doc/pointer.md +++ b/doc/pointer.md @@ -148,7 +148,7 @@ When using `p.Get(root)` or `GetValueByPointer(root, p)`, `root` is a (const) `V The other functions have two groups of signature. One group uses `Document& document` as parameter, another one uses `Value& root`. The first group uses `document.GetAllocator()` for creating values. And the second group needs user to supply an allocator, like the functions in DOM. -All examples above do not require an allocator parameter, because the parameter is a `Document&`. But if you want to resolve a pointer to a subtree. You need to supply it as in the following example: +All examples above do not require an allocator parameter, because the first parameter is a `Document&`. But if you want to resolve a pointer to a subtree, you need to supply the allocator as in the following example: ~~~cpp class Person { @@ -179,7 +179,7 @@ private: # Error Handling {#ErrorHandling} -A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns false. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information. +A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns `false`. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information. Note that, all resolving functions assumes valid pointer. Resolving with an invalid pointer causes assertion failure. @@ -215,7 +215,7 @@ It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`. # User-Supplied Tokens {#UserSuppliedTokens} -If a pointer will be resolved multiple times, it should be construct once, and then apply it to different DOMs or in different times. This reduce time and memory allocation for constructing `Pointer` multiple times. +If a pointer will be resolved multiple times, it should be constructed once, and then apply it to different DOMs or in different times. This reduce time and memory allocation for constructing `Pointer` multiple times. We can go one step further, to completely eliminate the parsing process and dynamic memory allocation, we can establish the token array directly: diff --git a/doc/pointer.zh-cn.md b/doc/pointer.zh-cn.md new file mode 100644 index 0000000..b6c446f --- /dev/null +++ b/doc/pointer.zh-cn.md @@ -0,0 +1,234 @@ +# Pointer + +## 状态: 实验性,应该会合进 v1.1 + +JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 简单得多,而且每个 JSON Pointer 仅指向单个值。 + +使用 RapidJSON 的 JSON Pointer 实现能简化一些 DOM 的操作。 + +[TOC] + +# JSON Pointer {#JsonPointer} + +一个 JSON Pointer 由一串(零至多个)token 所组成,每个 token 都有 `/` 前缀。每个 token 可以是一个字符串或数字。例如,给定一个 JSON: +~~~javascript +{ + "foo" : ["bar", "baz"], + "pi" : 3.1416 +} +~~~ + +以下的 JSON Pointer 解析为: + +1. `"/foo"` → `[ "bar", "baz" ]` +2. `"/foo/0"` → `"bar"` +3. `"/foo/1"` → `"baz"` +4. `"/pi"` → `3.1416` + +要注意,一个空 JSON Pointer `""` (零个token)解析为整个 JSON。 + +# 基本使用方法 {#BasicUsage} + +以下的代码范例不解自明。 + +~~~cpp +#include "rapidjson/pointer.h" + +// ... +Document d; + +// 使用 Set() 创建 DOM +Pointer("/project").Set(d, "RapidJSON"); +Pointer("/stars").Set(d, 10); + +// { "project" : "RapidJSON", "stars" : 10 } + +// 使用 Get() 访问 DOM。若该值不存在则返回 nullptr。 +if (Value* stars = Pointer("/stars").Get(d)) + stars->SetInt(stars->GetInt() + 1); + +// { "project" : "RapidJSON", "stars" : 11 } + +// Set() 和 Create() 自动生成父值(如果它们不存在)。 +Pointer("/a/b/0").Create(d); + +// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } } + +// GetWithDefault() 返回引用。若该值不存在则会深拷贝缺省值。 +Value& hello = Pointer("/hello").GetWithDefault(d, "world"); + +// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" } + +// Swap() 和 Set() 相似 +Value x("C++"); +Pointer("/hello").Swap(d, x); + +// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" } +// x 变成 "world" + +// 删去一个成员或元素,若值存在返回 true +bool success = Pointer("/a").Erase(d); +assert(success); + +// { "project" : "RapidJSON", "stars" : 10 } +~~~ + +# 辅助函数 {#HelperFunctions} + +由于面向对象的调用习惯可能不符直觉,RapidJSON 也提供了一些辅助函数,它们把成员函数包装成自由函数。 + +以下的例子与上面例子所做的事情完全相同。 + +~~~cpp +Document d; + +SetValueByPointer(d, "/project", "RapidJSON"); +SetValueByPointer(d, "/stars", 10); + +if (Value* stars = GetValueByPointer(d, "/stars")) + stars->SetInt(stars->GetInt() + 1); + +CreateValueByPointer(d, "/a/b/0"); + +Value& hello = GetValueByPointerWithDefault(d, "/hello", "world"); + +Value x("C++"); +SwapValueByPointer(d, "/hello", x); + +bool success = EraseValueByPointer(d, "/a"); +assert(success); +~~~ + +以下对比 3 种调用方式: + +1. `Pointer(source).(root, ...)` +2. `ValueByPointer(root, Pointer(source), ...)` +3. `ValueByPointer(root, source, ...)` + +# 解析 Pointer {#ResolvingPointer} + +`Pointer::Get()` 或 `GetValueByPointer()` 函数并不修改 DOM。若那些 token 不能匹配 DOM 里的值,这些函数便返回 `nullptr`。使用者可利用这个方法来检查一个值是否存在。 + +注意,数值 token 可表示数组索引或成员名字。解析过程中会按值的类型来匹配。 + +~~~javascript +{ + "0" : 123, + "1" : [456] +} +~~~ + +1. `"/0"` → `123` +2. `"/1/0"` → `456` + +Token `"0"` 在第一个 pointer 中被当作成员名字。它在第二个 pointer 中被当作成数组索引。 + +其他函数会改变 DOM,包括`Create()`、`GetWithDefault()`、`Set()`、`Swap()`。这些函数总是成功的。若一些父值不存在,就会创建它们。若父值类型不匹配 token,也会强行改变其类型。改变类型也意味着完全移除其 DOM 子树的内容。 + +例如,把上面的 JSON 解译至 `d` 之后, + +~~~cpp +SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } } +~~~ + +## 解析负号 token + +另外,[RFC6901] 定义了一个特殊 token `-` (单个负号),用于表示数组最后元素的下一个元素。 `Get()` 只会把此 token 当作成员名字 '"-"'。而其他函数则会以此解析数组,等同于对数组调用 `Value::PushBack()` 。 + +~~~cpp +Document d; +d.Parse("{\"foo\":[123]}"); +SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] } +SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 } +~~~ + +## 解析 Document 及 Value + +当使用 `p.Get(root)` 或 `GetValueByPointer(root, p)`,`root` 是一个(常数) `Value&`。这意味着,它也可以是 DOM 里的一个子树。 + +其他函数有两组签名。一组使用 `Document& document` 作为参数,另一组使用 `Value& root`。第一组使用 `document.GetAllocator()` 去创建值,而第二组则需要使用者提供一个 allocator,如同 DOM 里的函数。 + +以上例子都不需要 allocator 参数,因为它的第一个参数是 `Document&`。但如果你需要对一个子树进行解析,就需要如下面的例子般提供 allocator: + +~~~cpp +class Person { +public: + Person() { + document_ = new Document(); + // CreateValueByPointer() here no need allocator + SetLocation(CreateValueByPointer(*document_, "/residence"), ...); + SetLocation(CreateValueByPointer(*document_, "/office"), ...); + }; + +private: + void SetLocation(Value& location, const char* country, const char* addresses[2]) { + Value::Allocator& a = document_->GetAllocator(); + // SetValueByPointer() here need allocator + SetValueByPointer(location, "/country", country, a); + SetValueByPointer(location, "/address/0", address[0], a); + SetValueByPointer(location, "/address/1", address[1], a); + } + + // ... + + Document* document_; +}; +~~~ + +`Erase()` 或 `EraseValueByPointer()` 不需要 allocator。而且它们成功删除值之后会返回 `true`。 + +# 错误处理 {#ErrorHandling} + +`Pointer` 在其建构函数里会解译源字符串。若有解析错误,`Pointer::IsValid()` 返回 `false`。你可使用 `Pointer::GetParseErrorCode()` 和 `GetParseErrorOffset()` 去获取错信息。 + +要注意的是,所有解析函数都假设 pointer 是合法的。对一个非法 pointer 解析会做成断言失败。 + +# URI 片段表示方式 {#URIFragment} + +除了我们一直在使用的字符串方式表示 JSON pointer,[RFC6901]也定义了一个 JSON Pointer 的 URI 片段(fragment)表示方式。URI 片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax"。 + +URI 片段的主要分别是必然以 `#` (pound sign)开头,而一些字符也会以百分比编码成 UTF-8 序列。例如,以下的表展示了不同表示法下的 C/C++ 字符串常数。 + +字符串表示方式 | URI 片段表示方式 | Pointer Tokens (UTF-8) +----------------------|-----------------------------|------------------------ +`"/foo/0"` | `"#/foo/0"` | `{"foo", 0}` +`"/a~1b"` | `"#/a~1b"` | `{"a/b"}` +`"/m~0n"` | `"#/m~0n"` | `{"m~n"}` +`"/ "` | `"#/%20"` | `{" "}` +`"/\0"` | `"#/%00"` | `{"\0"}` +`"/€"` | `"#/%E2%82%AC"` | `{"€"}` + +RapidJSON 完全支持 URI 片段表示方式。它在解译时会自动检测 `#` 号。 + +# 字符串化 + +你也可以把一个 `Pointer` 字符串化,储存于字符串或其他输出流。例如: + +~~~ +Pointer p(...); +StringBuffer sb; +p.Stringify(sb); +std::cout << sb.GetString() << std::endl; +~~~ + +使用 `StringifyUriFragment()` 可以把 pointer 字符串化为 URI 片段表示法。 + +# 使用者提供的 tokens {#UserSuppliedTokens} + +若一个 pointer 会用于多次解析,它应该只被创建一次,然后再施于不同的 DOM ,或在不同时间做解析。这样可以避免多次创键 `Pointer`,节省时间和内存分配。 + +我们甚至可以再更进一步,完全消去解析过程及动态内存分配。我们可以直接生成 token 数组: + +~~~cpp +#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } +#define INDEX(i) { #i, sizeof(#i) - 1, i } + +static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; +static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); +// Equivalent to static const Pointer p("/foo/123"); +~~~ + +这种做法可能适合内存受限的系统。 + +[RFC3986]: https://tools.ietf.org/html/rfc3986 +[RFC6901]: https://tools.ietf.org/html/rfc6901 From 5512ec30f17bf771a442815c21d5e21cdbc6138b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 27 Oct 2015 13:36:36 -0700 Subject: [PATCH 18/98] Add Chinese pointer guide to doxygen --- doc/Doxyfile.zh-cn.in | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/Doxyfile.zh-cn.in b/doc/Doxyfile.zh-cn.in index 2f94553..ad73462 100644 --- a/doc/Doxyfile.zh-cn.in +++ b/doc/Doxyfile.zh-cn.in @@ -764,18 +764,19 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = ./readme.zh-cn.md \ - ./include/rapidjson/rapidjson.h \ - ./include/ \ - ./doc/features.zh-cn.md \ - ./doc/tutorial.zh-cn.md \ - ./doc/stream.zh-cn.md \ - ./doc/encoding.zh-cn.md \ - ./doc/dom.zh-cn.md \ - ./doc/sax.zh-cn.md \ - ./doc/performance.zh-cn.md \ - ./doc/internals.md \ - ./doc/faq.zh-cn.md +INPUT = readme.zh-cn.md \ + include/rapidjson/rapidjson.h \ + include/ \ + doc/features.zh-cn.md \ + doc/tutorial.zh-cn.md \ + doc/pointer.md \ + doc/stream.zh-cn.md \ + doc/encoding.zh-cn.md \ + doc/dom.zh-cn.md \ + doc/sax.zh-cn.md \ + doc/performance.zh-cn.md \ + doc/internals.md \ + doc/faq.zh-cn.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses From e602aab7f4f00bdf25f9fc681af059b2a1ad3600 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 27 Oct 2015 14:34:35 -0700 Subject: [PATCH 19/98] Fix language for pointer --- doc/Doxyfile.zh-cn.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile.zh-cn.in b/doc/Doxyfile.zh-cn.in index ad73462..873022a 100644 --- a/doc/Doxyfile.zh-cn.in +++ b/doc/Doxyfile.zh-cn.in @@ -769,7 +769,7 @@ INPUT = readme.zh-cn.md \ include/ \ doc/features.zh-cn.md \ doc/tutorial.zh-cn.md \ - doc/pointer.md \ + doc/pointer.zh-cn.md \ doc/stream.zh-cn.md \ doc/encoding.zh-cn.md \ doc/dom.zh-cn.md \ From 82329825c3485cf4dd7778047543a784256d9baf Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 28 Oct 2015 15:57:13 -0700 Subject: [PATCH 20/98] Fixes full-width spaces --- doc/pointer.zh-cn.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/pointer.zh-cn.md b/doc/pointer.zh-cn.md index b6c446f..b340deb 100644 --- a/doc/pointer.zh-cn.md +++ b/doc/pointer.zh-cn.md @@ -4,7 +4,7 @@ JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 简单得多,而且每个 JSON Pointer 仅指向单个值。 -使用 RapidJSON 的 JSON Pointer 实现能简化一些 DOM 的操作。 +使用 RapidJSON 的 JSON Pointer 实现能简化一些 DOM 的操作。 [TOC] @@ -146,7 +146,7 @@ SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 } 当使用 `p.Get(root)` 或 `GetValueByPointer(root, p)`,`root` 是一个(常数) `Value&`。这意味着,它也可以是 DOM 里的一个子树。 -其他函数有两组签名。一组使用 `Document& document` 作为参数,另一组使用 `Value& root`。第一组使用 `document.GetAllocator()` 去创建值,而第二组则需要使用者提供一个 allocator,如同 DOM 里的函数。 +其他函数有两组签名。一组使用 `Document& document` 作为参数,另一组使用 `Value& root`。第一组使用 `document.GetAllocator()` 去创建值,而第二组则需要使用者提供一个 allocator,如同 DOM 里的函数。 以上例子都不需要 allocator 参数,因为它的第一个参数是 `Document&`。但如果你需要对一个子树进行解析,就需要如下面的例子般提供 allocator: From c6cb74bff8967fcff0f85684d1a56a83ce1e8c1d Mon Sep 17 00:00:00 2001 From: stunney Date: Thu, 29 Oct 2015 11:57:56 -0400 Subject: [PATCH 21/98] Adding coapp definition To create a nupkg, call CoApp's Write-NuGetPackage .\rapidjson.autopkg -defines:MYVERSION=1.0.2 (or whatever version you want to call it) --- .gitignore | 1 + rapidjson.autopkg | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 rapidjson.autopkg diff --git a/.gitignore b/.gitignore index 95acb0c..d97a316 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Testing install_manifest.txt Doxyfile DartConfiguration.tcl +*.nupkg diff --git a/rapidjson.autopkg b/rapidjson.autopkg new file mode 100644 index 0000000..50307cf --- /dev/null +++ b/rapidjson.autopkg @@ -0,0 +1,73 @@ +nuget { + nuspec { + id = rapidjson; + version : ${MYVERSION}; + title: "rapidjson"; + authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.0.2"}; + owners: {"@lsantos (github)"}; + licenseUrl: "http://www.opensource.org/licenses/mit-license.php"; + projectUrl: "https://github.com/miloyip/rapidjson/"; + iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png"; + requireLicenseAcceptance:false; + summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API"; + + // if you need to span several lines you can prefix a string with an @ symbol (exactly like c# does). + description: @"Rapidjson is an attempt to create the fastest JSON parser and generator. + + - Small but complete. Supports both SAX and DOM style API. SAX parser only a few hundred lines of code. + - Fast. In the order of magnitude of strlen(). Optionally supports SSE2/SSE4.2 for acceleration. + - Self-contained. Minimal dependency on standard libraries. No BOOST, not even STL. + - Compact. Each JSON value is 16 or 20 bytes for 32 or 64-bit machines respectively (excluding text string storage). With the custom memory allocator, parser allocates memory compactly during parsing. + - Full RFC4627 compliance. Supports UTF-8, UTF-16 and UTF-32. + - Support both in-situ parsing (directly decode strings into the source JSON text) and non-destructive parsing (decode strings into new buffers). + - Parse number to int/unsigned/int64_t/uint64_t/double depending on input + - Support custom memory allocation. Also, the default memory pool allocator can also be supplied with a user buffer (such as a buffer allocated on user's heap or - programme stack) to minimize allocation. + + As the name implies, rapidjson is inspired by rapidxml."; + + releaseNotes: @" +Added + Add Value::XXXMember(...) overloads for std::string (#335) + +Fixed + Include rapidjson.h for all internal/error headers. + Parsing some numbers incorrectly in full-precision mode (kFullPrecisionParseFlag) (#342) + Fix alignment of 64bit platforms (#328) + Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502) + +Changed + CMakeLists for include as a thirdparty in projects (#334, #337) + Change Document::ParseStream() to use stack allocator for Reader (ffbe386)"; + + copyright: "Copyright 2015"; + tags: { native, coapp, JSON, nativepackage }; + language: en-US; + }; + + dependencies { + packages : { + //TODO: Add dependecies here in [pkg.name]/[version] form per newline + //zlib/[1.2.8], + }; + } + + // the files that go into the content folders + files { + #defines { + SDK_ROOT = .\; + } + + // grab all the files in the include folder + // the folder that contains all the .h files will + // automatically get added to the Includes path. + nestedinclude += { + #destination = ${d_include}rapidjson; + "${SDK_ROOT}include\rapidjson\**\*.h" + }; + }; + + targets { + // We're trying to be standard about these sorts of thing. (Will help with config.h later :D) + //Defines += HAS_EQCORE; + }; +} \ No newline at end of file From d6912d07cd89c02fb59ed315586cae6fbb403c21 Mon Sep 17 00:00:00 2001 From: stunney Date: Thu, 29 Oct 2015 13:53:42 -0400 Subject: [PATCH 22/98] Updating LicenseURL based on @miloyip 's suggestion https://github.com/miloyip/rapidjson/pull/460#issuecomment-152232015 --- rapidjson.autopkg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapidjson.autopkg b/rapidjson.autopkg index 50307cf..0e5cd32 100644 --- a/rapidjson.autopkg +++ b/rapidjson.autopkg @@ -5,7 +5,7 @@ nuget { title: "rapidjson"; authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.0.2"}; owners: {"@lsantos (github)"}; - licenseUrl: "http://www.opensource.org/licenses/mit-license.php"; + licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt"; projectUrl: "https://github.com/miloyip/rapidjson/"; iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png"; requireLicenseAcceptance:false; From dceb7bed940ad14979c97d34fcc1e03a384acb9e Mon Sep 17 00:00:00 2001 From: stunney Date: Thu, 29 Oct 2015 14:02:12 -0400 Subject: [PATCH 23/98] Usage comment Adding usage comment at the top of the file for knowledge sharing --- rapidjson.autopkg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rapidjson.autopkg b/rapidjson.autopkg index 0e5cd32..d91aaef 100644 --- a/rapidjson.autopkg +++ b/rapidjson.autopkg @@ -1,4 +1,6 @@ nuget { + //Usage: Write-NuGetPackage rapidjson.autopkg -defines:MYVERSION=1.0.2 + //Be sure you are running Powershell 3.0 and have the CoApp powershell extensions installed properly. nuspec { id = rapidjson; version : ${MYVERSION}; From c8d298bc9eb68c281c98914df08fecd191947938 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Mon, 16 Nov 2015 21:32:09 +0100 Subject: [PATCH 24/98] documenttest.cpp: EXPECT_THROW when checking empty allocator (closes #469) In the MoveConstructor/MoveAssignment tests, a check for a `NULL` allocator return has been used to check for the correct moved-from state of a Document. After the merge of #426, the GetAllocator call fails with an assertion, if the allocator of a GenericDocument is NULL. Check for the throw, instead of NULL in the move-related tests. Tested with GCC 4.9 on Linux with C++11 enabled. Reported-by: @woldendans --- test/unittest/documenttest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 83325a7..0d84194 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -381,7 +381,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) { EXPECT_TRUE(a.IsNull()); EXPECT_TRUE(b.IsArray()); EXPECT_EQ(3u, b.Size()); - EXPECT_EQ(&a.GetAllocator(), (void*)0); + EXPECT_THROW(a.GetAllocator(), AssertException); EXPECT_EQ(&b.GetAllocator(), &allocator); b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); @@ -394,7 +394,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) { EXPECT_TRUE(b.IsNull()); EXPECT_TRUE(c.IsObject()); EXPECT_EQ(2u, c.MemberCount()); - EXPECT_EQ(&b.GetAllocator(), (void*)0); + EXPECT_THROW(b.GetAllocator(), AssertException); EXPECT_EQ(&c.GetAllocator(), &allocator); } @@ -475,7 +475,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) { EXPECT_TRUE(a.IsNull()); EXPECT_TRUE(b.IsArray()); EXPECT_EQ(3u, b.Size()); - EXPECT_EQ(&a.GetAllocator(), (void*)0); + EXPECT_THROW(a.GetAllocator(), AssertException); EXPECT_EQ(&b.GetAllocator(), &allocator); b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); @@ -489,7 +489,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) { EXPECT_TRUE(b.IsNull()); EXPECT_TRUE(c.IsObject()); EXPECT_EQ(2u, c.MemberCount()); - EXPECT_EQ(&b.GetAllocator(), (void*)0); + EXPECT_THROW(b.GetAllocator(), AssertException); EXPECT_EQ(&c.GetAllocator(), &allocator); } From 07672da09815eefba4db31c538dc6590672f21f6 Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Wed, 25 Nov 2015 19:45:47 +0100 Subject: [PATCH 25/98] fix Document::Parse(const Ch*) for transcoding To allow for an UTF16-Document to Parse(UTF8), the Parse() argument has to be UTF8-compatible. --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 8da86ab..1ee4fb6 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1951,7 +1951,7 @@ public: \param str Read-only zero-terminated string to be parsed. */ template - GenericDocument& Parse(const Ch* str) { + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); From 98959e28207c154713e7691c35245460c4c87bfb Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 26 Nov 2015 22:30:59 +0100 Subject: [PATCH 26/98] GenericDocument: add implicit conversion to ParseResult To simplify the error handling, this commit adds an implicit conversion of GenericDocument to ParseResult, allowing code like (already in the documentation): ParseResult ok = doc.Parse(json); if (!ok) // ... --- include/rapidjson/document.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 1ee4fb6..b708a5a 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1986,6 +1986,17 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } + //! Implicit conversion to get the last parse result + /*! \return \ref ParseResult of the last parse operation + + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ + operator ParseResult() const { return parseResult_; } //!@} //! Get the allocator of this document. From 9378001e355a1f470a5ff8a49a9834545d17c541 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 26 Nov 2015 22:33:14 +0100 Subject: [PATCH 27/98] documenttest.cpp: check/use conversion from Document to ParseResult --- test/unittest/documenttest.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 0d84194..e4d1432 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -28,6 +28,7 @@ void ParseCheck(DocumentType& doc) { typedef typename DocumentType::ValueType ValueType; EXPECT_FALSE(doc.HasParseError()); + EXPECT_TRUE((ParseResult)doc); EXPECT_TRUE(doc.IsObject()); @@ -99,13 +100,18 @@ TEST(Document, UnchangedOnParseError) { Document doc; doc.SetArray().PushBack(0, doc.GetAllocator()); - doc.Parse("{]"); + ParseResult err = doc.Parse("{]"); EXPECT_TRUE(doc.HasParseError()); + EXPECT_EQ(err.Code(), doc.GetParseError()); + EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); EXPECT_TRUE(doc.IsArray()); EXPECT_EQ(doc.Size(), 1u); - doc.Parse("{}"); + err = doc.Parse("{}"); EXPECT_FALSE(doc.HasParseError()); + EXPECT_FALSE(err.IsError()); + EXPECT_EQ(err.Code(), doc.GetParseError()); + EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); EXPECT_TRUE(doc.IsObject()); EXPECT_EQ(doc.MemberCount(), 0u); } From fe89676a9e5a3fdc9b66b914a5076217adb523ff Mon Sep 17 00:00:00 2001 From: Wenhao Liu Date: Sat, 28 Nov 2015 22:40:43 +0800 Subject: [PATCH 28/98] fix a compatibility issue with doxygen --- doc/faq.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/faq.md b/doc/faq.md index 8f441fe..cbcd4f1 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -106,59 +106,59 @@ Call one of the `SetXXX()` methods - they call destructor which deallocates DOM data: - ``` + ~~~~~~~~~~cpp Document d; ... d.SetObject(); // clear and minimize - ``` + ~~~~~~~~~~ Alternatively, use equivalent of the [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize): - ``` + ~~~~~~~~~~cpp Value(kObjectType).Swap(d); - ``` + ~~~~~~~~~~ or equivalent, but sightly longer to type: - ``` + ~~~~~~~~~~cpp d.Swap(Value(kObjectType).Move()); - ``` + ~~~~~~~~~~ 9. How to insert a document node into another document? Let's take the following two DOM trees represented as JSON documents: - ``` + ~~~~~~~~~~cpp Document person; person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}"); Document address; address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}"); - ``` + ~~~~~~~~~~ Let's assume we want to merge them in such way that the whole `address` document becomes a node of the `person`: - ``` + ~~~~~~~~~~js { "person": { "name": { "first": "Adam", "last": "Thomas" }, "address": { "city": "Moscow", "street": "Quiet" } } } - ``` + ~~~~~~~~~~ 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. 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 nenber of the value: - ``` + ~~~~~~~~~~cpp Documnet address(person.GetAllocator()); ... person["person"].AddMember("address", address["address"], person.GetAllocator()); - ``` + ~~~~~~~~~~ Alternatively, if we don't want to explicitly refer to the root value of `address` by name, we can refer to it via iterator: - ``` + ~~~~~~~~~~cpp auto addressRoot = address.MemberBegin(); person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator()); - ``` + ~~~~~~~~~~ Second way is to deep-clone the value from the address document: - ``` + ~~~~~~~~~~cpp Value addressValue = Value(address["address"], person.GetAllocator()); person["person"].AddMember("address", addressValue, person.GetAllocator()); - ``` + ~~~~~~~~~~ ## Document/Value (DOM) From 06f62e38f7e7fe1a24c90aa34f7e23887d89b634 Mon Sep 17 00:00:00 2001 From: Wenhao Liu Date: Sun, 29 Nov 2015 00:12:29 +0800 Subject: [PATCH 29/98] fix typos and dead links, sync faq.zh-cn.md --- doc/faq.md | 2 +- doc/faq.zh-cn.md | 65 +++++++++++++++++++++++++++++++++++++++++-- doc/sax.zh-cn.md | 12 ++++---- doc/tutorial.zh-cn.md | 6 ++-- 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/doc/faq.md b/doc/faq.md index cbcd4f1..1b0541c 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -142,7 +142,7 @@ 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. - 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 nenber of the value: + 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()); ... diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md index c6e7557..7127283 100644 --- a/doc/faq.zh-cn.md +++ b/doc/faq.zh-cn.md @@ -28,7 +28,7 @@ 6. 怎样安装RapidJSON? - 见[安装一节](readme.zh-cn.md)。 + 见[安装一节](../readme.zh-cn.md#安装)。 7. RapidJSON能否运行于我的平台? @@ -52,7 +52,7 @@ 12. 有没有其他替代品? - 有许多替代品。例如nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)列出了一些开源的C/C++ JSON库。[json.org](http://www.json.org/)也有一个列表。 + 有许多替代品。例如[nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)列出了一些开源的C/C++ JSON库。[json.org](http://www.json.org/)也有一个列表。 ## JSON @@ -98,10 +98,69 @@ 错误信息存储在`ParseResult`,它包含错误代号及偏移值(从JSON开始至错误处的字符数目)。可以把错误代号翻译为人类可读的错误讯息。 -7. 为可不只使用`double`去表示JSON number? +7. 为何不只使用`double`去表示JSON number? 一些应用需要使用64位无号/有号整数。这些整数不能无损地转换成`double`。因此解析器会检测一个JSON number是否能转换至各种整数类型及`double`。 +8. 如何清空并最小化`document`或`value`的容量? + + 调用 `SetXXX()` 方法 - 这些方法会调用析构函数,并重建空的Object或Array: + + ~~~~~~~~~~cpp + Document d; + ... + d.SetObject(); // clear and minimize + ~~~~~~~~~~ + + 另外,也可以参考在 [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize)中的一种等价的方法: + ~~~~~~~~~~cpp + Value(kObjectType).Swap(d); + ~~~~~~~~~~ + 或者,使用这个稍微长一点的代码也能完成同样的事情: + ~~~~~~~~~~cpp + d.Swap(Value(kObjectType).Move()); + ~~~~~~~~~~ + +9. 如何将一个`document`节点插入到另一个`document`中? + + 比如有以下两个document(DOM): + ~~~~~~~~~~cpp + Document person; + person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}"); + + Document address; + address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}"); + ~~~~~~~~~~ + 假设我们希望将整个 `address` 插入到`person`中,作为其的一个子节点: + ~~~~~~~~~~js + { "person": { + "name": { "first": "Adam", "last": "Thomas" }, + "address": { "city": "Moscow", "street": "Quiet" } + } + } + ~~~~~~~~~~ + + 在插入节点的过程中需要注意`document`和`value`的生命周期并且正确地使用allocator进行内存分配和管理。 + + 一个简单有效的方法就是修改上述`address`变量的定义,让其使用`person`的allocator初始化,然后将其添加到根节点。 + + ~~~~~~~~~~cpp + Documnet address(person.GetAllocator()); + ... + person["person"].AddMember("address", address["address"], person.GetAllocator()); + ~~~~~~~~~~ + 当然,如果你不想通过显式地写出`address`的key来得到其值,可以使用迭代器来实现: + ~~~~~~~~~~cpp + auto addressRoot = address.MemberBegin(); + person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator()); + ~~~~~~~~~~ + + 此外,还可以通过深拷贝address document来实现: + ~~~~~~~~~~cpp + Value addressValue = Value(address["address"], person.GetAllocator()); + person["person"].AddMember("address", addressValue, person.GetAllocator()); + ~~~~~~~~~~ + ## Document/Value (DOM) 1. 什么是转移语意?为什么? diff --git a/doc/sax.zh-cn.md b/doc/sax.zh-cn.md index cad5a58..f8dc7b9 100644 --- a/doc/sax.zh-cn.md +++ b/doc/sax.zh-cn.md @@ -175,7 +175,7 @@ bool Parse(InputStream& is, Handler& handler); # Writer {#Writer} -`Reader`把JSON转换(解析)成为事件。`Writer`完全做相反的事情。它把事件转换成JSON。 +`Reader`把JSON转换(解析)成为事件。`Writer`做完全相反的事情。它把事件转换成JSON。 `Writer`是非常容易使用的。若你的应用程序只需把一些数据转换成JSON,可能直接使用`Writer`,会比建立一个`Document`然后用`Writer`把它转换成JSON更加方便。 @@ -265,7 +265,7 @@ public: ## PrettyWriter {#PrettyWriter} -`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但就适合人类阅读。 +`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但不适合人类阅读。 因此,RapidJSON提供了一个`PrettyWriter`,它在输出中加入缩进及换行。 @@ -386,13 +386,13 @@ Error: Terminate parsing due to Handler error. at offset 59 near '} }...' ~~~~~~~~~~ -第一个JSON(`json1`)被成功地解析至`MessageMap`。由于`MessageMap`是一个`std::map`,列印次序按键值排序。此次序与JSON中的次序不同。 +第一个JSON(`json1`)被成功地解析至`MessageMap`。由于`MessageMap`是一个`std::map`,打印次序按键值排序。此次序与JSON中的次序不同。 -在第二个JSON(`json2`)中,`foo`的值是一个空object。由于它是一个object,`MessageHandler::StartObject()`会被调用。然而,在`state_ = kExpectValue`的情况下,该函数会返回`false`,并令到解析过程终止。错误代码是`kParseErrorTermination`。 +在第二个JSON(`json2`)中,`foo`的值是一个空object。由于它是一个object,`MessageHandler::StartObject()`会被调用。然而,在`state_ = kExpectValue`的情况下,该函数会返回`false`,并导致解析过程终止。错误代码是`kParseErrorTermination`。 ## 过滤JSON {#Filtering} -如前面提及过,`Writer`可处理`Reader`发出的事件。`condense`例子简单地设置`Writer`作为一个`Reader`的处理器,因此它能移除JSON中的所有空白字符。`pretty`例子使用同样的关系,只是以`PrettyWriter`取代`Writer`。因此`pretty`能够重新格式化JSON,加入缩进及换行。 +如前面提及过,`Writer`可处理`Reader`发出的事件。`example/condense/condense.cpp`例子简单地设置`Writer`作为一个`Reader`的处理器,因此它能移除JSON中的所有空白字符。`example/pretty/pretty.cpp`例子使用同样的关系,只是以`PrettyWriter`取代`Writer`。因此`pretty`能够重新格式化JSON,加入缩进及换行。 实际上,我们可以使用SAX风格API去加入(多个)中间层去过滤JSON的内容。例如`capitalize`例子可以把所有JSON string改为大写。 @@ -472,5 +472,5 @@ int main(int, char*[]) { ["HELLO\nWORLD"] ~~~~~~~~~~ -我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对些一些处理情况,用DOM会比SAX更容易实现。 +我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对于处理某些情况,用DOM会比SAX更容易实现。 diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md index 3ecaec8..37808b0 100644 --- a/doc/tutorial.zh-cn.md +++ b/doc/tutorial.zh-cn.md @@ -2,7 +2,7 @@ 本教程简介文件对象模型(Document Object Model, DOM)API。 -如[用法一览](readme.zh-cn.md)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。 +如[用法一览](../readme.zh-cn.md#用法一览)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。 [TOC] @@ -123,7 +123,7 @@ a[3] = 4 你可以用整数字面量访问元素,如`a[0]`、`a[1]`、`a[2]`。 -Array与`std::vector`相似,除了使用索引,也可使用迭待器来访问所有元素。 +Array与`std::vector`相似,除了使用索引,也可使用迭代器来访问所有元素。 ~~~~~~~~~~cpp for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) printf("%d ", itr->GetInt()); @@ -461,7 +461,7 @@ contact.AddMember(key, val, document.GetAllocator()); * `bool RemoveMember(const Ch* name)`:使用键名来移除成员(线性时间复杂度)。 * `bool RemoveMember(const Value& name)`:除了`name`是一个Value,和上一行相同。 -* `MemberIterator RemoveMember(MemberIterator)`:使用迭待器移除成员(_常数_时间复杂度)。 +* `MemberIterator RemoveMember(MemberIterator)`:使用迭代器移除成员(_常数_时间复杂度)。 * `MemberIterator EraseMember(MemberIterator)`:和上行相似但维持成员次序(线性时间复杂度)。 * `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`:移除一个范围内的成员,维持次序(线性时间复杂度)。 From db0a03a43c9aa8d665b5a950e72b21f36eaff9c4 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 30 Nov 2015 17:22:06 +0800 Subject: [PATCH 30/98] Fix #483 by using the correct value type --- include/rapidjson/pointer.h | 6 +++--- test/unittest/pointertest.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 5d2aa8d..d873163 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -390,7 +390,7 @@ public: bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { - v->PushBack(Value().Move(), allocator); + v->PushBack(ValueType().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } @@ -408,7 +408,7 @@ public: if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) - v->PushBack(Value().Move(), allocator); + v->PushBack(ValueType().Move(), allocator); exist = false; } v = &((*v)[t->index]); @@ -416,7 +416,7 @@ public: else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { - v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator); + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end exist = false; } diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index 7ec3f72..9ad6b45 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -1456,3 +1456,38 @@ TEST(Pointer, Ambiguity) { EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt()); } } + +// https://github.com/miloyip/rapidjson/issues/483 +namespace myjson { + +class MyAllocator +{ +public: + static const bool kNeedFree = true; + void * Malloc(size_t _size) { return malloc(_size); } + void * Realloc(void *_org_p, size_t _org_size, size_t _new_size) { (void)_org_size; return realloc(_org_p, _new_size); } + static void Free(void *_p) { return free(_p); } +}; + +typedef rapidjson::GenericDocument< + rapidjson::UTF8<>, + rapidjson::MemoryPoolAllocator< MyAllocator >, + MyAllocator + > Document; + +typedef rapidjson::GenericPointer< + ::myjson::Document::ValueType, + MyAllocator + > Pointer; + +typedef ::myjson::Document::ValueType Value; + +} + +TEST(Pointer, Issue483) { + std::string mystr, path; + myjson::Document document; + myjson::Value value(rapidjson::kStringType); + value.SetString(mystr.c_str(), mystr.length(), document.GetAllocator()); + myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator()); +} From 5b268e65080e9595ffc136363d3ecd51f27a5de5 Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Fri, 27 Nov 2015 16:46:42 +0100 Subject: [PATCH 31/98] use with C++ linkage on Windows ARM Instead of commenting that we should, just do include with C++ linkage when compiling for Windows on ARM. Actually, omitting the C linkage really should be enough here. --- include/rapidjson/msinttypes/stdint.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/msinttypes/stdint.h b/include/rapidjson/msinttypes/stdint.h index a26fff4..3d4477b 100644 --- a/include/rapidjson/msinttypes/stdint.h +++ b/include/rapidjson/msinttypes/stdint.h @@ -89,14 +89,14 @@ #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(_M_ARM) extern "C" { #endif # include -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(_M_ARM) } #endif From e7063978617e0145f8a58716d02737ba194379af Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Mon, 30 Nov 2015 17:38:58 +0100 Subject: [PATCH 32/98] detect little endian for Microsoft ARM targets When _MSC_VER and _M_ARM is defined, this is some Windows ARM target using little-endian byte order. --- include/rapidjson/rapidjson.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 4c4d983..7034f48 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -211,6 +211,8 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && defined(_M_ARM) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else From 8b265fe4b6ab7a9910e7a0b342caa8c5b61cdeeb Mon Sep 17 00:00:00 2001 From: miloyip Date: Sun, 6 Dec 2015 11:38:53 +0800 Subject: [PATCH 33/98] Fixes #489 --- test/unittest/pointertest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index 9ad6b45..d36b59d 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -306,7 +306,7 @@ TEST(Pointer, Parse_URIFragment) { GenericPointer > > p(L"#/%C2%A2"); EXPECT_TRUE(p.IsValid()); EXPECT_EQ(1u, p.GetTokenCount()); - EXPECT_EQ(0x00A2, p.GetTokens()[0].name[0]); + EXPECT_EQ((UTF16<>::Ch)0x00A2, p.GetTokens()[0].name[0]); EXPECT_EQ(1u, p.GetTokens()[0].length); } @@ -315,7 +315,7 @@ TEST(Pointer, Parse_URIFragment) { GenericPointer > > p(L"#/%E2%82%AC"); EXPECT_TRUE(p.IsValid()); EXPECT_EQ(1u, p.GetTokenCount()); - EXPECT_EQ(0x20AC, p.GetTokens()[0].name[0]); + EXPECT_EQ((UTF16<>::Ch)0x20AC, p.GetTokens()[0].name[0]); EXPECT_EQ(1u, p.GetTokens()[0].length); } From a1c4f325cab87c0fa2ce5b2737750adbc905b279 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 6 Dec 2015 13:44:47 +0800 Subject: [PATCH 34/98] Temporarily remove git clone single-branch https://github.com/travis-ci/travis-ci/issues/5225 --- travis-doxygen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis-doxygen.sh b/travis-doxygen.sh index 1023108..e9eb6b9 100755 --- a/travis-doxygen.sh +++ b/travis-doxygen.sh @@ -66,7 +66,7 @@ gh_pages_prepare() [ ! -d "html" ] || \ abort "Doxygen target directory already exists." git --version - git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html + git clone -b gh-pages "${GITHUB_CLONE}" html cd html # setup git config (with defaults) git config user.name "${GIT_NAME-travis}" From 7899a3c125f9654968de77cdc431f0eb384429c0 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 16 Dec 2015 09:40:39 +0100 Subject: [PATCH 35/98] encodings.h: fix typo in preprocessor condition (closes #494) --- 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 bc3cd81..7b740d3 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -618,7 +618,7 @@ struct Transcoder { RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSV_VER) +#if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif From 74c8dcfd5791c4f11e6d52fdc15047b0622dd8af Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 18:34:04 +0800 Subject: [PATCH 36/98] Fix clang -Weverything --- example/CMakeLists.txt | 2 +- example/capitalize/capitalize.cpp | 4 +- example/condense/condense.cpp | 2 +- example/messagereader/messagereader.cpp | 9 +- example/pretty/pretty.cpp | 2 +- example/prettyauto/prettyauto.cpp | 2 +- example/serialize/serialize.cpp | 8 +- example/tutorial/tutorial.cpp | 8 +- include/rapidjson/allocators.h | 2 +- include/rapidjson/document.h | 102 +++++++++--------- include/rapidjson/encodedstream.h | 15 ++- include/rapidjson/encodings.h | 134 +++++++++++++----------- include/rapidjson/error/en.h | 10 +- include/rapidjson/error/error.h | 17 ++- include/rapidjson/filereadstream.h | 13 ++- include/rapidjson/internal/biginteger.h | 2 +- include/rapidjson/internal/diyfp.h | 10 ++ include/rapidjson/internal/ieee754.h | 2 +- include/rapidjson/internal/stack.h | 4 +- include/rapidjson/internal/strtod.h | 8 +- include/rapidjson/memorystream.h | 4 +- include/rapidjson/pointer.h | 42 +++++--- include/rapidjson/prettywriter.h | 2 +- include/rapidjson/rapidjson.h | 38 +++++++ include/rapidjson/reader.h | 63 +++++++---- include/rapidjson/writer.h | 37 ++++--- test/CMakeLists.txt | 2 +- test/unittest/CMakeLists.txt | 2 +- test/unittest/allocatorstest.cpp | 12 +-- test/unittest/documenttest.cpp | 72 ++++++------- test/unittest/encodedstreamtest.cpp | 19 ++-- test/unittest/encodingstest.cpp | 5 +- test/unittest/filestreamtest.cpp | 7 +- test/unittest/itoatest.cpp | 8 +- test/unittest/jsoncheckertest.cpp | 24 ++--- test/unittest/pointertest.cpp | 6 +- test/unittest/prettywritertest.cpp | 6 +- test/unittest/readertest.cpp | 37 ++++--- test/unittest/simdtest.cpp | 2 +- test/unittest/strtodtest.cpp | 6 +- test/unittest/unittest.cpp | 6 +- test/unittest/unittest.h | 24 ++++- test/unittest/valuetest.cpp | 66 ++++++------ 43 files changed, 504 insertions(+), 342 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 8063d89..127f71e 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -20,7 +20,7 @@ include_directories("../include/") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/example/capitalize/capitalize.cpp b/example/capitalize/capitalize.cpp index a19ed50..adc32b5 100644 --- a/example/capitalize/capitalize.cpp +++ b/example/capitalize/capitalize.cpp @@ -27,7 +27,7 @@ struct CapitalizeFilter { bool String(const char* str, SizeType length, bool) { buffer_.clear(); for (SizeType i = 0; i < length; i++) - buffer_.push_back(std::toupper(str[i])); + buffer_.push_back(static_cast(std::toupper(str[i]))); return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string } bool StartObject() { return out_.StartObject(); } @@ -58,7 +58,7 @@ int main(int, char*[]) { // JSON reader parse from the input stream and let writer generate the output. CapitalizeFilter > filter(writer); if (!reader.Parse(is, filter)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + fprintf(stderr, "\nError(%u): %s\n", static_cast(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode())); return 1; } diff --git a/example/condense/condense.cpp b/example/condense/condense.cpp index d77f2c7..5c038d0 100644 --- a/example/condense/condense.cpp +++ b/example/condense/condense.cpp @@ -24,7 +24,7 @@ int main(int, char*[]) { // JSON reader parse from the input stream and let writer generate the output. if (!reader.Parse(is, writer)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + fprintf(stderr, "\nError(%u): %s\n", static_cast(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode())); return 1; } diff --git a/example/messagereader/messagereader.cpp b/example/messagereader/messagereader.cpp index 50255b3..d19292b 100644 --- a/example/messagereader/messagereader.cpp +++ b/example/messagereader/messagereader.cpp @@ -26,13 +26,16 @@ struct MessageHandler case kExpectObjectStart: state_ = kExpectNameOrObjectEnd; return true; - default: + case kExpectNameOrObjectEnd: + case kExpectValue: return false; } } bool String(const char* str, SizeType length, bool) { switch (state_) { + case kExpectObjectStart: + return false; case kExpectNameOrObjectEnd: name_ = string(str, length); state_ = kExpectValue; @@ -41,8 +44,6 @@ struct MessageHandler messages_.insert(MessageMap::value_type(name_, string(str, length))); state_ = kExpectNameOrObjectEnd; return true; - default: - return false; } } @@ -63,7 +64,7 @@ struct MessageHandler RAPIDJSON_DIAG_POP #endif -void ParseMessages(const char* json, MessageMap& messages) { +static void ParseMessages(const char* json, MessageMap& messages) { Reader reader; MessageHandler handler; StringStream ss(json); diff --git a/example/pretty/pretty.cpp b/example/pretty/pretty.cpp index 164e388..2185cfe 100644 --- a/example/pretty/pretty.cpp +++ b/example/pretty/pretty.cpp @@ -22,7 +22,7 @@ int main(int, char*[]) { // JSON reader parse from the input stream and let writer generate the output. if (!reader.Parse(is, writer)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + fprintf(stderr, "\nError(%u): %s\n", static_cast(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode())); return 1; } diff --git a/example/prettyauto/prettyauto.cpp b/example/prettyauto/prettyauto.cpp index 0d30968..700dc19 100644 --- a/example/prettyauto/prettyauto.cpp +++ b/example/prettyauto/prettyauto.cpp @@ -48,7 +48,7 @@ int main(int, char*[]) { // JSON reader parse from the input stream and let writer generate the output. //if (!reader.Parse(is, writer)) { if (!reader.Parse(eis, writer)) { // CHANGED - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + fprintf(stderr, "\nError(%u): %s\n", static_cast(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode())); return 1; } diff --git a/example/serialize/serialize.cpp b/example/serialize/serialize.cpp index 7427939..6c5e5c2 100644 --- a/example/serialize/serialize.cpp +++ b/example/serialize/serialize.cpp @@ -18,10 +18,10 @@ protected: void Serialize(Writer& writer) const { // This base class just write out name-value pairs, without wrapping within an object. writer.String("name"); -#ifdef RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING writer.String(name_); #else - writer.String(name_.c_str(), (SizeType)name_.length()); // Supplying length of string is faster. + writer.String(name_.c_str(), static_cast(name_.length())); // Supplying length of string is faster. #endif writer.String("age"); writer.Uint(age_); @@ -44,10 +44,10 @@ public: writer.StartObject(); writer.String("school"); -#ifdef RAPIDJSON_HAS_STDSTRING +#if RAPIDJSON_HAS_STDSTRING writer.String(school_); #else - writer.String(school_.c_str(), (SizeType)school_.length()); + writer.String(school_.c_str(), static_cast(school_.length())); #endif writer.String("GPA"); diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index 206fdb9..354057a 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -121,17 +121,17 @@ int main(int, char*[]) { // This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer. Value author; { - char buffer[10]; - int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string. + char buffer2[10]; + int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string. - author.SetString(buffer, static_cast(len), document.GetAllocator()); + author.SetString(buffer2, static_cast(len), document.GetAllocator()); // Shorter but slower version: // document["hello"].SetString(buffer, document.GetAllocator()); // Constructor version: // Value author(buffer, len, document.GetAllocator()); // Value author(buffer, document.GetAllocator()); - memset(buffer, 0, sizeof(buffer)); // For demonstration purpose. + memset(buffer2, 0, sizeof(buffer2)); // For demonstration purpose. } // Variable 'buffer' is unusable now but 'author' has already made a copy. document.AddMember("author", author, document.GetAllocator()); diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index 6be2776..05e3b0c 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -199,7 +199,7 @@ public: return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast(newSize - originalSize); increment = RAPIDJSON_ALIGN(increment); if (chunkHead_->size + increment <= chunkHead_->capacity) { diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index b708a5a..8fde16c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -25,36 +25,18 @@ #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#elif defined(__GNUC__) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +#ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_HAS_STDSTRING - -#ifndef RAPIDJSON_HAS_STDSTRING -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation -#else -#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default -#endif -/*! \def RAPIDJSON_HAS_STDSTRING - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for \c std::string - - By defining this preprocessor symbol to \c 1, several convenience functions for using - \ref rapidjson::GenericValue with \c std::string are enabled, especially - for construction and comparison. - - \hideinitializer -*/ -#endif // !defined(RAPIDJSON_HAS_STDSTRING) - -#if RAPIDJSON_HAS_STDSTRING -#include -#endif // RAPIDJSON_HAS_STDSTRING - #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::iterator, std::random_access_iterator_tag #endif @@ -260,6 +242,7 @@ struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array +#ifndef __clang__ // -Wdocumentation /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than @@ -282,11 +265,13 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the GenericValue instead. */ +#endif template GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer +#ifndef __clang__ // -Wdocumentation /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. @@ -305,16 +290,19 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the GenericValue instead. */ +#endif explicit GenericStringRef(const CharType* str) : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } //! Create constant string reference from pointer and length +#ifndef __clang__ // -Wdocumentation /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ +#endif GenericStringRef(const CharType* str, SizeType len) : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } @@ -654,7 +642,7 @@ public: */ template GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { - RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); + RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); new (this) GenericValue(rhs, allocator); return *this; @@ -736,7 +724,9 @@ public: else return data_.n.u64 == rhs.data_.n.u64; - default: // kTrueType, kFalseType, kNullType + case kNullType: + case kFalseType: + case kTrueType: return true; } } @@ -864,8 +854,14 @@ public: return member->value; else { RAPIDJSON_ASSERT(false); // see above note - static GenericValue NullValue; - return NullValue; + + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; + + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); } } template @@ -1235,7 +1231,7 @@ public: MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); - std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); + std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); data_.o.size -= (last - first); return pos; } @@ -1328,7 +1324,7 @@ public: GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { - data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); + data_.a.elements = static_cast(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))); data_.a.capacity = newCapacity; } return *this; @@ -1435,7 +1431,7 @@ public: ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); - std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); + std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); data_.a.size -= (last - first); return pos; } @@ -1455,8 +1451,8 @@ public: if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) + if ((flags_ & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } @@ -1562,8 +1558,7 @@ public: case kStringType: return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); - default: - RAPIDJSON_ASSERT(GetType() == kNumberType); + case kNumberType: if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); @@ -1628,9 +1623,9 @@ private: enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } - inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. @@ -1683,7 +1678,7 @@ private: void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { flags_ = kArrayFlag; if (count) { - data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); + data_.a.elements = static_cast(allocator.Malloc(count * sizeof(GenericValue))); std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); } else @@ -1695,7 +1690,7 @@ private: void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { flags_ = kObjectFlag; if (count) { - data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); + data_.o.members = static_cast(allocator.Malloc(count * sizeof(Member))); std::memcpy(data_.o.members, members, count * sizeof(Member)); } else @@ -1720,7 +1715,7 @@ private: } else { flags_ = kCopyStringFlag; data_.s.length = s.length; - str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); data_.s.str = str; } std::memcpy(str, s, s.length * sizeof(Ch)); @@ -1847,7 +1842,7 @@ public: //! Exchange the contents of this document with those of another. /*! - \param other Another document. + \param rhs Another document. \note Constant complexity. \see GenericValue::Swap */ @@ -1987,6 +1982,7 @@ public: size_t GetErrorOffset() const { return parseResult_.Offset(); } //! Implicit conversion to get the last parse result +#ifndef __clang // -Wdocumentation /*! \return \ref ParseResult of the last parse operation \code @@ -1996,6 +1992,7 @@ public: printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); \endcode */ +#endif operator ParseResult() const { return parseResult_; } //!@} @@ -2046,7 +2043,7 @@ private: bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); return true; } @@ -2109,7 +2106,10 @@ GenericValue::GenericValue(const GenericValue(&rhs.data_); break; @@ -2118,7 +2118,15 @@ GenericValue::GenericValue(const GenericValue class EncodedOutputStream { @@ -142,7 +147,7 @@ private: // FF FE UTF-16LE // EF BB BF UTF-8 - const unsigned char* c = (const unsigned char *)is_->Peek4(); + const unsigned char* c = reinterpret_cast(is_->Peek4()); if (!c) return; @@ -193,7 +198,7 @@ private: //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. - \tparam InputByteStream type of output byte stream to be wrapped. + \tparam OutputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { @@ -254,6 +259,10 @@ private: RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index 7b740d3..f37f9e1 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -122,17 +122,17 @@ struct UTF8 { template static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) -#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) - Ch c = is.Take(); + typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { - *codepoint = (unsigned char)c; + *codepoint = static_cast(c); return true; } - unsigned char type = GetRange((unsigned char)c); - *codepoint = (0xFF >> type) & (unsigned char)c; + unsigned char type = GetRange(static_cast(c)); + *codepoint = (0xFF >> type) & static_cast(c); bool result = true; switch (type) { case 2: TAIL(); return result; @@ -152,7 +152,7 @@ struct UTF8 { template static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c; COPY(); @@ -160,7 +160,7 @@ struct UTF8 { return true; bool result = true; - switch (GetRange((unsigned char)c)) { + switch (GetRange(static_cast(c))) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; @@ -196,12 +196,12 @@ struct UTF8 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - if ((unsigned char)c != 0xEFu) return c; + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; c = is.Take(); - if ((unsigned char)c != 0xBBu) return c; + if (static_cast(c) != 0xBBu) return c; c = is.Take(); - if ((unsigned char)c != 0xBFu) return c; + if (static_cast(c) != 0xBFu) return c; c = is.Take(); return c; } @@ -209,13 +209,15 @@ struct UTF8 { template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); + return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); } template @@ -262,15 +264,15 @@ struct UTF16 { template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - Ch c = is.Take(); + typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { - *codepoint = c; + *codepoint = static_cast(c); return true; } else if (c <= 0xDBFF) { - *codepoint = (c & 0x3FF) << 10; + *codepoint = (static_cast(c) & 0x3FF) << 10; c = is.Take(); - *codepoint |= (c & 0x3FF); + *codepoint |= (static_cast(c) & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } @@ -281,8 +283,8 @@ struct UTF16 { static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - Ch c; - os.Put(c = is.Take()); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { @@ -300,28 +302,29 @@ struct UTF16LE : UTF16 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; + return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - return c; + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); } }; @@ -332,28 +335,29 @@ struct UTF16BE : UTF16 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; + return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(is.Take()); + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFEu); os.Put(0xFFu); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); } }; @@ -406,32 +410,35 @@ struct UTF32LE : UTF32 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 24; - return c; + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 24) & 0xFFu); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); } }; @@ -442,32 +449,35 @@ struct UTF32BE : UTF32 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 24; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 24) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); } }; @@ -493,29 +503,29 @@ struct ASCII { template static bool Decode(InputStream& is, unsigned* codepoint) { - unsigned char c = static_cast(is.Take()); + uint8_t c = static_cast(is.Take()); *codepoint = c; return c <= 0X7F; } template static bool Validate(InputStream& is, OutputStream& os) { - unsigned char c = is.Take(); - os.Put(c); + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); return c <= 0x7F; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - return c; + uint8_t c = static_cast(Take(is)); + return static_cast(c); } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); + return static_cast(is.Take()); } template diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h index d5f9caa..81932e2 100644 --- a/include/rapidjson/error/en.h +++ b/include/rapidjson/error/en.h @@ -12,8 +12,8 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef RAPIDJSON_ERROR_EN_H__ -#define RAPIDJSON_ERROR_EN_H__ +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ #include "error.h" @@ -54,12 +54,10 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - - default: - return RAPIDJSON_ERROR_STRING("Unknown error."); } + return RAPIDJSON_ERROR_STRING("Unknown error."); } RAPIDJSON_NAMESPACE_END -#endif // RAPIDJSON_ERROR_EN_H__ +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index f9094fb..95cb31a 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -12,11 +12,16 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef RAPIDJSON_ERROR_ERROR_H__ -#define RAPIDJSON_ERROR_ERROR_H__ +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ @@ -99,7 +104,7 @@ enum ParseErrorCode { \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { - +public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. @@ -143,4 +148,8 @@ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); RAPIDJSON_NAMESPACE_END -#endif // RAPIDJSON_ERROR_ERROR_H__ +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index 78ee403..588f7f1 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -18,6 +18,11 @@ #include "rapidjson.h" #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). @@ -45,8 +50,8 @@ public: size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } + void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } @@ -85,4 +90,8 @@ private: RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_FILESTREAM_H_ diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h index 4477cf5..9d3e88c 100755 --- a/include/rapidjson/internal/biginteger.h +++ b/include/rapidjson/internal/biginteger.h @@ -240,7 +240,7 @@ private: uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10u + (unsigned)(*p - '0'); + r = r * 10u + static_cast(*p - '0'); } return r; } diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index 7a55ee3..9a62c2c 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -35,6 +35,11 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + struct DiyFp { DiyFp() {} @@ -242,6 +247,11 @@ inline DiyFp GetCachedPower10(int exp, int *outExp) { RAPIDJSON_DIAG_POP #endif +#ifdef __clang__ +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) +#endif + } // namespace internal RAPIDJSON_NAMESPACE_END diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h index 2fdaf54..6890f89 100644 --- a/include/rapidjson/internal/ieee754.h +++ b/include/rapidjson/internal/ieee754.h @@ -53,7 +53,7 @@ public: else if (order <= -1074) return 0; else - return (unsigned)order + 1074; + return static_cast(order) + 1074; } private: diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 82f23dd..dcc9757 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -132,7 +132,7 @@ public: } template - T* Bottom() { return (T*)stack_; } + T* Bottom() { return reinterpret_cast(stack_); } bool HasAllocator() const { return allocator_ != 0; @@ -168,7 +168,7 @@ private: void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size - stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h index a1b8211..89590c4 100644 --- a/include/rapidjson/internal/strtod.h +++ b/include/rapidjson/internal/strtod.h @@ -149,7 +149,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit v = v.Normalize(); error <<= -v.e; - const int dExp = (int)decimalPosition - (int)i + exp; + const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); @@ -206,7 +206,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { const BigInteger dInt(decimals, length); - const int dExp = (int)decimalPosition - (int)length + exp; + const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) @@ -246,8 +246,8 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t // Trim right-most digits const int kMaxDecimalDigit = 780; - if ((int)length > kMaxDecimalDigit) { - int delta = (int(length) - kMaxDecimalDigit); + if (static_cast(length) > kMaxDecimalDigit) { + int delta = (static_cast(length) - kMaxDecimalDigit); exp += delta; decimalPosition -= static_cast(delta); length = kMaxDecimalDigit; diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h index 99feae5..03c04e8 100644 --- a/include/rapidjson/memorystream.h +++ b/include/rapidjson/memorystream.h @@ -41,8 +41,8 @@ struct MemoryStream { size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } + void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index d873163..f58ce35 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -253,11 +253,12 @@ public: */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; - SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer; + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); buffer[length] = '\0'; if (sizeof(Ch) == 1) { - Token token = { (Ch*)buffer, length, index }; + Token token = { reinterpret_cast(buffer), length, index }; return Append(token, allocator); } else { @@ -271,7 +272,7 @@ public: //! Append a token by value, and return a new Pointer /*! - \param value Value (either Uint or String) to be appended. + \param token token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ @@ -435,7 +436,6 @@ public: //! Creates a value in a document. /*! \param document A document to be resolved. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ @@ -472,7 +472,11 @@ public: return 0; v = &((*v)[t->index]); break; - default: + case kNullType: + case kFalseType: + case kTrueType: + case kStringType: + case kNumberType: return 0; } } @@ -525,7 +529,7 @@ public: //! Query a value in a subtree with default primitive value. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -555,7 +559,7 @@ public: //! Query a value in a document with default primitive value. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -601,7 +605,7 @@ public: //! Set a primitive value in a subtree. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -637,7 +641,7 @@ public: //! Set a primitive value in a document. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -701,7 +705,11 @@ public: return false; v = &((*v)[t->index]); break; - default: + case kNullType: + case kFalseType: + case kTrueType: + case kStringType: + case kNumberType: return false; } } @@ -714,7 +722,11 @@ public: return false; v->Erase(v->Begin() + last->index); return true; - default: + case kNullType: + case kFalseType: + case kTrueType: + case kStringType: + case kNumberType: return false; } } @@ -759,11 +771,13 @@ private: } //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ +#endif void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); @@ -857,7 +871,7 @@ private: *name++ = c; } - token->length = name - token->name; + token->length = static_cast(name - token->name); if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator @@ -944,6 +958,8 @@ private: */ class PercentDecodeStream { public: + typedef Ch Ch; + //! Constructor /*! \param source Start of the stream @@ -973,7 +989,7 @@ private: return c; } - size_t Tell() const { return src_ - head_; } + size_t Tell() const { return static_cast(src_ - head_); } bool IsValid() const { return valid_; } private: diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index fff8886..adfff4f 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -186,7 +186,7 @@ protected: void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, indentChar_, count); + PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 7034f48..41790cf 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -119,6 +119,31 @@ #define RAPIDJSON_NAMESPACE_END } #endif +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE @@ -351,7 +376,9 @@ RAPIDJSON_NAMESPACE_END // Adopt from boost #ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; @@ -367,7 +394,9 @@ RAPIDJSON_NAMESPACE_END #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif +#ifndef __clang__ //!@endcond +#endif /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time @@ -435,6 +464,15 @@ RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIAG_* +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NORETURN_SUFFIX + +#if defined(__clang__) +#define RAPIDJSON_NORETURN_SUFFIX __attribute__ ((noreturn)) +#else +#define RAPIDJSON_NORETURN_SUFFIX +#endif + /////////////////////////////////////////////////////////////////////////////// // C++11 features diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index b56f3b5..4cb7d50 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -39,6 +39,11 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) @@ -263,7 +268,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; @@ -272,11 +277,11 @@ inline const char *SkipWhitespace_SIMD(const char* p) { // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (;; p += 16) { - const __m128i s = _mm_load_si128((const __m128i *)p); - const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); if (r != 0) { // some of characters is non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; @@ -698,7 +703,7 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { @@ -737,9 +742,8 @@ private: if (c == '\\') { // Escape is.Take(); Ch e = is.Take(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { - os.Put(escape[(unsigned char)e]); - } + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[static_cast(e)]) + os.Put(static_cast(escape[static_cast(e)])); else if (e == 'u') { // Unicode unsigned codepoint = ParseHex4(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; @@ -765,7 +769,7 @@ private: } else if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); - else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + else if (static_cast(c) < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); else { if (parseFlags & kParseValidateEncodingFlag ? @@ -806,7 +810,7 @@ private: ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put((char)Base::is.Peek()); + stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } @@ -937,10 +941,10 @@ private: } } - d = (double)i64; + d = static_cast(i64); #else // Use double to store significand in 32-bit architecture - d = use64bit ? (double)i64 : (double)i; + d = static_cast(use64bit ? i64 : i); #endif useDouble = true; } @@ -977,10 +981,10 @@ private: } if (s.Peek() >= '0' && s.Peek() <= '9') { - exp = s.Take() - '0'; + exp = static_cast(s.Take() - '0'); if (expMinus) { while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); + exp = exp * 10 + static_cast(s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent s.Take(); @@ -990,7 +994,7 @@ private: else { // positive exp int maxExp = 308 - expFrac; while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); + exp = exp * 10 + static_cast(s.Take() - '0'); if (exp > maxExp) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); } @@ -1075,11 +1079,11 @@ private: IterativeParsingArrayFinishState, // Single value state - IterativeParsingValueState, - - cIterativeParsingStateCount + IterativeParsingValueState }; + enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; + // Tokens enum Token { LeftBracketToken = 0, @@ -1121,8 +1125,8 @@ private: #undef N16 //!@endcond - if (sizeof(Ch) == 1 || unsigned(c) < 256) - return (Token)tokenMap[(unsigned char)c]; + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); else return NumberToken; } @@ -1288,7 +1292,7 @@ private: } }; // End of G - return (IterativeParsingState)G[state][token]; + return static_cast(G[state][token]); } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). @@ -1413,7 +1417,9 @@ private: } } - default: + case IterativeParsingStartState: + case IterativeParsingFinishState: + case IterativeParsingValueState: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. @@ -1450,7 +1456,13 @@ private: case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; + case IterativeParsingErrorState: + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingObjectFinishState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: + case IterativeParsingArrayFinishState: + case IterativeParsingValueState: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; } } @@ -1499,6 +1511,11 @@ typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 8fcffbe..a450456 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -23,15 +23,16 @@ #include "stringbuffer.h" #include // placement new -#if RAPIDJSON_HAS_STDSTRING -#include -#endif - #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! JSON writer @@ -205,7 +206,7 @@ protected: char buffer[11]; const char* end = internal::i32toa(i, buffer); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + os_->Put(static_cast(*p)); return true; } @@ -213,7 +214,7 @@ protected: char buffer[10]; const char* end = internal::u32toa(u, buffer); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + os_->Put(static_cast(*p)); return true; } @@ -221,7 +222,7 @@ protected: char buffer[21]; const char* end = internal::i64toa(i64, buffer); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + os_->Put(static_cast(*p)); return true; } @@ -229,7 +230,7 @@ protected: char buffer[20]; char* end = internal::u64toa(u64, buffer); for (char* p = buffer; p != end; ++p) - os_->Put(*p); + os_->Put(static_cast(*p)); return true; } @@ -237,12 +238,12 @@ protected: char buffer[25]; char* end = internal::dtoa(d, buffer); for (char* p = buffer; p != end; ++p) - os_->Put(*p); + os_->Put(static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F @@ -259,7 +260,7 @@ protected: GenericStringStream is(str); while (is.Tell() < length) { const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) @@ -290,15 +291,15 @@ protected: os_->Put(hexDigits[(trail ) & 15]); } } - else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && escape[static_cast(c)]) { is.Take(); os_->Put('\\'); - os_->Put(escape[(unsigned char)c]); - if (escape[(unsigned char)c] == 'u') { + os_->Put(static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') { os_->Put('0'); os_->Put('0'); - os_->Put(hexDigits[(unsigned char)c >> 4]); - os_->Put(hexDigits[(unsigned char)c & 0xF]); + os_->Put(hexDigits[static_cast(c) >> 4]); + os_->Put(hexDigits[static_cast(c) & 0xF]); } } else @@ -392,4 +393,8 @@ RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c698af4..11c1b04 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,7 +9,7 @@ IF(GTESTSRC_FOUND) endif() add_subdirectory(${GTEST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/googletest) - include_directories(${GTEST_INCLUDE_DIR}) + include_directories(SYSTEM ${GTEST_INCLUDE_DIR}) set(TEST_LIBRARIES gtest gtest_main) diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index fd2eb4d..35b800f 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -21,7 +21,7 @@ set(UNITTEST_SOURCES if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp index 792a88e..f70e672 100644 --- a/test/unittest/allocatorstest.cpp +++ b/test/unittest/allocatorstest.cpp @@ -22,21 +22,21 @@ template void TestAllocator(Allocator& a) { EXPECT_TRUE(a.Malloc(0) == 0); - uint8_t* p = (uint8_t*)a.Malloc(100); + uint8_t* p = static_cast(a.Malloc(100)); EXPECT_TRUE(p != 0); for (size_t i = 0; i < 100; i++) - p[i] = (uint8_t)i; + p[i] = static_cast(i); // Expand - uint8_t* q = (uint8_t*)a.Realloc(p, 100, 200); + uint8_t* q = static_cast(a.Realloc(p, 100, 200)); EXPECT_TRUE(q != 0); for (size_t i = 0; i < 100; i++) EXPECT_EQ(i, q[i]); for (size_t i = 100; i < 200; i++) - q[i] = (uint8_t)i; + q[i] = static_cast(i); // Shrink - uint8_t *r = (uint8_t*)a.Realloc(q, 200, 150); + uint8_t *r = static_cast(a.Realloc(q, 200, 150)); EXPECT_TRUE(r != 0); for (size_t i = 0; i < 150; i++) EXPECT_EQ(i, r[i]); @@ -56,7 +56,7 @@ TEST(Allocator, MemoryPoolAllocator) { MemoryPoolAllocator<> a; TestAllocator(a); - for (int i = 1; i < 1000; i++) { + for (size_t i = 1; i < 1000; i++) { EXPECT_TRUE(a.Malloc(i) != 0); EXPECT_LE(a.Size(), a.Capacity()); } diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index e4d1432..cdc4c31 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -28,7 +28,7 @@ void ParseCheck(DocumentType& doc) { typedef typename DocumentType::ValueType ValueType; EXPECT_FALSE(doc.HasParseError()); - EXPECT_TRUE((ParseResult)doc); + EXPECT_TRUE(static_cast(doc)); EXPECT_TRUE(doc.IsObject()); @@ -63,8 +63,8 @@ void ParseCheck(DocumentType& doc) { const ValueType& a = doc["a"]; EXPECT_TRUE(a.IsArray()); EXPECT_EQ(4u, a.Size()); - for (SizeType i = 0; i < 4; i++) - EXPECT_EQ(i + 1, a[i].GetUint()); + for (SizeType j = 0; j < 4; j++) + EXPECT_EQ(j + 1, a[j].GetUint()); } template @@ -118,15 +118,15 @@ TEST(Document, UnchangedOnParseError) { static FILE* OpenEncodedFile(const char* filename) { const char *paths[] = { - "encodings/%s", - "bin/encodings/%s", - "../bin/encodings/%s", - "../../bin/encodings/%s", - "../../../bin/encodings/%s" + "encodings", + "bin/encodings", + "../bin/encodings", + "../../bin/encodings", + "../../../bin/encodings" }; char buffer[1024]; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { - sprintf(buffer, paths[i], filename); + sprintf(buffer, "%s/%s", paths[i], filename); FILE *fp = fopen(buffer, "rb"); if (fp) return fp; @@ -157,22 +157,22 @@ TEST(Document, ParseStream_EncodedInputStream) { StringBuffer bos; typedef EncodedOutputStream, StringBuffer> OutputStream; OutputStream eos(bos, false); // Not writing BOM - Writer, UTF8<> > writer(eos); - d.Accept(writer); - { - // Condense the original file and compare. - FILE *fp = OpenEncodedFile("utf8.json"); - FileReadStream is(fp, buffer, sizeof(buffer)); - Reader reader; - StringBuffer bos2; - Writer writer(bos2); - reader.Parse(is, writer); - fclose(fp); - - EXPECT_EQ(bos.GetSize(), bos2.GetSize()); - EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); + Writer, UTF8<> > writer(eos); + d.Accept(writer); } + + // Condense the original file and compare. + fp = OpenEncodedFile("utf8.json"); + FileReadStream is(fp, buffer, sizeof(buffer)); + Reader reader; + StringBuffer bos2; + Writer writer2(bos2); + reader.Parse(is, writer2); + fclose(fp); + + EXPECT_EQ(bos.GetSize(), bos2.GetSize()); + EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); } TEST(Document, ParseStream_AutoUTFInputStream) { @@ -199,19 +199,17 @@ TEST(Document, ParseStream_AutoUTFInputStream) { Writer writer(bos); d.Accept(writer); - { - // Condense the original file and compare. - FILE *fp = OpenEncodedFile("utf8.json"); - FileReadStream is(fp, buffer, sizeof(buffer)); - Reader reader; - StringBuffer bos2; - Writer writer(bos2); - reader.Parse(is, writer); - fclose(fp); + // Condense the original file and compare. + fp = OpenEncodedFile("utf8.json"); + FileReadStream is(fp, buffer, sizeof(buffer)); + Reader reader; + StringBuffer bos2; + Writer writer2(bos2); + reader.Parse(is, writer2); + fclose(fp); - EXPECT_EQ(bos.GetSize(), bos2.GetSize()); - EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); - } + EXPECT_EQ(bos.GetSize(), bos2.GetSize()); + EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); } TEST(Document, Swap) { @@ -263,12 +261,16 @@ TEST(Document, Swap) { struct OutputStringStream : public std::ostringstream { typedef char Ch; + virtual ~OutputStringStream(); + void Put(char c) { put(c); } void Flush() {} }; +OutputStringStream::~OutputStringStream() {} + TEST(Document, AcceptWriter) { Document doc; doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); diff --git a/test/unittest/encodedstreamtest.cpp b/test/unittest/encodedstreamtest.cpp index 8cef208..f6d6935 100644 --- a/test/unittest/encodedstreamtest.cpp +++ b/test/unittest/encodedstreamtest.cpp @@ -25,6 +25,7 @@ using namespace rapidjson; class EncodedStreamTest : public ::testing::Test { public: EncodedStreamTest() : json_(), length_() {} + virtual ~EncodedStreamTest(); virtual void SetUp() { json_ = ReadFile("utf8.json", true, &length_); @@ -42,15 +43,15 @@ private: protected: static FILE* Open(const char* filename) { const char *paths[] = { - "encodings/%s", - "bin/encodings/%s", - "../bin/encodings/%s", - "../../bin/encodings/%s", - "../../../bin/encodings/%s" + "encodings", + "bin/encodings", + "../bin/encodings", + "../../bin/encodings", + "../../../bin/encodings" }; char buffer[1024]; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { - sprintf(buffer, paths[i], filename); + sprintf(buffer, "%s/%s", paths[i], filename); FILE *fp = fopen(buffer, "rb"); if (fp) return fp; @@ -67,9 +68,9 @@ protected: } fseek(fp, 0, SEEK_END); - *outLength = (size_t)ftell(fp); + *outLength = static_cast(ftell(fp)); fseek(fp, 0, SEEK_SET); - char* buffer = (char*)malloc(*outLength + 1); + char* buffer = static_cast(malloc(*outLength + 1)); size_t readLength = fread(buffer, 1, *outLength, fp); buffer[readLength] = '\0'; fclose(fp); @@ -248,6 +249,8 @@ protected: size_t length_; }; +EncodedStreamTest::~EncodedStreamTest() {} + TEST_F(EncodedStreamTest, EncodedInputStream) { TestEncodedInputStream, UTF8<> >("utf8.json"); TestEncodedInputStream, UTF8<> >("utf8bom.json"); diff --git a/test/unittest/encodingstest.cpp b/test/unittest/encodingstest.cpp index b697d91..be59cc9 100644 --- a/test/unittest/encodingstest.cpp +++ b/test/unittest/encodingstest.cpp @@ -240,7 +240,6 @@ static const unsigned kCodepointRanges[] = { // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. #define UTF8_ACCEPT 0u -#define UTF8_REJECT 12u static const unsigned char utf8d[] = { // The first part of the table maps bytes to character classes that @@ -298,7 +297,7 @@ TEST(EncodingsTest, UTF8) { unsigned decodedCount = 0; for (const char* s = encodedStr; *s; ++s) - if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) { + if (!decode(&state, &decodedCodepoint, static_cast(*s))) { EXPECT_EQ(codepoint, decodedCodepoint); decodedCount++; } @@ -355,7 +354,7 @@ TEST(EncodingsTest, UTF16) { unsigned state = 0; UTF16<>::Ch buffer[3], *p = &buffer[0]; for (const char* s = utf8os.GetString(); *s; ++s) { - if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) + if (!decode(&state, &decodedCodepoint, static_cast(*s))) break; } diff --git a/test/unittest/filestreamtest.cpp b/test/unittest/filestreamtest.cpp index 2850b56..539da70 100644 --- a/test/unittest/filestreamtest.cpp +++ b/test/unittest/filestreamtest.cpp @@ -22,6 +22,7 @@ using namespace rapidjson; class FileStreamTest : public ::testing::Test { public: FileStreamTest() : filename_(), json_(), length_() {} + virtual ~FileStreamTest(); virtual void SetUp() { const char *paths[] = { @@ -42,9 +43,9 @@ public: ASSERT_TRUE(fp != 0); fseek(fp, 0, SEEK_END); - length_ = (size_t)ftell(fp); + length_ = static_cast(ftell(fp)); fseek(fp, 0, SEEK_SET); - json_ = (char*)malloc(length_ + 1); + json_ = static_cast(malloc(length_ + 1)); size_t readLength = fread(json_, 1, length_, fp); json_[readLength] = '\0'; fclose(fp); @@ -65,6 +66,8 @@ protected: size_t length_; }; +FileStreamTest::~FileStreamTest() {} + TEST_F(FileStreamTest, FileReadStream) { FILE *fp = fopen(filename_, "rb"); ASSERT_TRUE(fp != 0); diff --git a/test/unittest/itoatest.cpp b/test/unittest/itoatest.cpp index 5ceb99f..9c3107d 100644 --- a/test/unittest/itoatest.cpp +++ b/test/unittest/itoatest.cpp @@ -30,28 +30,28 @@ template <> struct Traits { enum { kBufferSize = 11 }; enum { kMaxDigit = 10 }; - static uint32_t Negate(uint32_t x) { return x; }; + static uint32_t Negate(uint32_t x) { return x; } }; template <> struct Traits { enum { kBufferSize = 12 }; enum { kMaxDigit = 10 }; - static int32_t Negate(int32_t x) { return -x; }; + static int32_t Negate(int32_t x) { return -x; } }; template <> struct Traits { enum { kBufferSize = 21 }; enum { kMaxDigit = 20 }; - static uint64_t Negate(uint64_t x) { return x; }; + static uint64_t Negate(uint64_t x) { return x; } }; template <> struct Traits { enum { kBufferSize = 22 }; enum { kMaxDigit = 20 }; - static int64_t Negate(int64_t x) { return -x; }; + static int64_t Negate(int64_t x) { return -x; } }; template diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index 34f8569..8991667 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -20,16 +20,16 @@ using namespace rapidjson; static char* ReadFile(const char* filename, size_t& length) { const char *paths[] = { - "jsonchecker/%s", - "bin/jsonchecker/%s", - "../bin/jsonchecker/%s", - "../../bin/jsonchecker/%s", - "../../../bin/jsonchecker/%s" + "jsonchecker", + "bin/jsonchecker", + "../bin/jsonchecker", + "../../bin/jsonchecker", + "../../../bin/jsonchecker" }; char buffer[1024]; FILE *fp = 0; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { - sprintf(buffer, paths[i], filename); + sprintf(buffer, "%s/%s", paths[i], filename); fp = fopen(buffer, "rb"); if (fp) break; @@ -39,9 +39,9 @@ static char* ReadFile(const char* filename, size_t& length) { return 0; fseek(fp, 0, SEEK_END); - length = (size_t)ftell(fp); + length = static_cast(ftell(fp)); fseek(fp, 0, SEEK_SET); - char* json = (char*)malloc(length + 1); + char* json = static_cast(malloc(length + 1)); size_t readLength = fread(json, 1, length, fp); json[readLength] = '\0'; fclose(fp); @@ -68,10 +68,10 @@ TEST(JsonChecker, Reader) { } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - document.Parse((const char*)json); + document.Parse(json); EXPECT_TRUE(document.HasParseError()); - document.Parse((const char*)json); + document.Parse(json); EXPECT_TRUE(document.HasParseError()); free(json); @@ -88,10 +88,10 @@ TEST(JsonChecker, Reader) { } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - document.Parse((const char*)json); + document.Parse(json); EXPECT_FALSE(document.HasParseError()); - document.Parse((const char*)json); + document.Parse(json); EXPECT_FALSE(document.HasParseError()); free(json); diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index d36b59d..eee9ff7 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -306,7 +306,7 @@ TEST(Pointer, Parse_URIFragment) { GenericPointer > > p(L"#/%C2%A2"); EXPECT_TRUE(p.IsValid()); EXPECT_EQ(1u, p.GetTokenCount()); - EXPECT_EQ((UTF16<>::Ch)0x00A2, p.GetTokens()[0].name[0]); + EXPECT_EQ(static_cast::Ch>(0x00A2), p.GetTokens()[0].name[0]); EXPECT_EQ(1u, p.GetTokens()[0].length); } @@ -315,7 +315,7 @@ TEST(Pointer, Parse_URIFragment) { GenericPointer > > p(L"#/%E2%82%AC"); EXPECT_TRUE(p.IsValid()); EXPECT_EQ(1u, p.GetTokenCount()); - EXPECT_EQ((UTF16<>::Ch)0x20AC, p.GetTokens()[0].name[0]); + EXPECT_EQ(static_cast::Ch>(0x20AC), p.GetTokens()[0].name[0]); EXPECT_EQ(1u, p.GetTokens()[0].length); } @@ -1488,6 +1488,6 @@ TEST(Pointer, Issue483) { std::string mystr, path; myjson::Document document; myjson::Value value(rapidjson::kStringType); - value.SetString(mystr.c_str(), mystr.length(), document.GetAllocator()); + value.SetString(mystr.c_str(), static_cast(mystr.length()), document.GetAllocator()); myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator()); } diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp index 1a63c82..d3c69c0 100644 --- a/test/unittest/prettywritertest.cpp +++ b/test/unittest/prettywritertest.cpp @@ -149,13 +149,13 @@ TEST(PrettyWriter, FileWriteStream) { fp = fopen(filename, "rb"); fseek(fp, 0, SEEK_END); - size_t size = (size_t)ftell(fp); + size_t size = static_cast(ftell(fp)); fseek(fp, 0, SEEK_SET); - char* json = (char*)malloc(size + 1); + char* json = static_cast(malloc(size + 1)); size_t readLength = fread(json, 1, size, fp); json[readLength] = '\0'; fclose(fp); remove(filename); EXPECT_STREQ(kPrettyJson, json); free(json); -} \ No newline at end of file +} diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 71d7113..056ccb4 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -27,6 +27,11 @@ RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(float-equal) #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(variadic-macros) +#endif + template struct ParseBoolHandler : BaseReaderHandler, ParseBoolHandler > { ParseBoolHandler() : step_(0) {} @@ -159,12 +164,12 @@ TEST(Reader, ParseNumber_Integer) { u.u |= r(); char buffer[32]; - if (u.u >= 4294967296ULL) { + if (u.u > 4294967295) { *internal::u64toa(u.u, buffer) = '\0'; TEST_INTEGER(ParseUint64Handler, buffer, u.u); } - if (u.i <= -2147483649LL) { + if (u.i < -2147483648) { *internal::i64toa(u.i, buffer) = '\0'; TEST_INTEGER(ParseInt64Handler, buffer, u.i); } @@ -456,7 +461,7 @@ struct ParseStringHandler : BaseReaderHandler(malloc((length + 1) * sizeof(typename Encoding::Ch))); memcpy(const_cast(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); } else @@ -639,11 +644,11 @@ TEST(Reader, ParseString_Error) { { char e[] = { '[', '\"', 0, '\"', ']', '\0' }; for (unsigned char c = 0x80u; c <= 0xBFu; c++) { - e[2] = c; + e[2] = static_cast(c); ParseErrorCode error = TestString >(e); EXPECT_EQ(kParseErrorStringInvalidEncoding, error); if (error != kParseErrorStringInvalidEncoding) - std::cout << (unsigned)(unsigned char)c << std::endl; + std::cout << static_cast(c) << std::endl; } } @@ -651,7 +656,7 @@ TEST(Reader, ParseString_Error) { { char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' }; for (unsigned c = 0xC0u; c <= 0xFFu; c++) { - e[2] = (char)c; + e[2] = static_cast(c); TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e); } } @@ -771,7 +776,7 @@ struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { default: ADD_FAILURE(); return false; } } - bool Uint(unsigned i) { return Int(i); } + bool Uint(unsigned i) { return Int(static_cast(i)); } bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } bool String(const char* str, size_t, bool) { switch(step_) { @@ -1024,19 +1029,19 @@ public: Ch Peek() const { int c = is_.peek(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; + return c == std::char_traits::eof() ? '\0' : static_cast(c); } Ch Take() { int c = is_.get(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; + return c == std::char_traits::eof() ? '\0' : static_cast(c); } - size_t Tell() const { return (size_t)is_.tellg(); } + size_t Tell() const { return static_cast(is_.tellg()); } Ch* PutBegin() { assert(false); return 0; } - void Put(Ch) { assert(false); } - void Flush() { assert(false); } + void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { assert(false); } + void Flush() RAPIDJSON_NORETURN_SUFFIX { assert(false); } size_t PutEnd(Ch*) { assert(false); return 0; } private: @@ -1143,7 +1148,7 @@ struct IterativeParsingReaderHandler { bool EndObject(SizeType c) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_ENDOBJECT; - Logs[LogCount++] = (int)c; + Logs[LogCount++] = static_cast(c); return true; } @@ -1152,7 +1157,7 @@ struct IterativeParsingReaderHandler { bool EndArray(SizeType c) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_ENDARRAY; - Logs[LogCount++] = (int)c; + Logs[LogCount++] = static_cast(c); return true; } }; @@ -1455,3 +1460,7 @@ TEST(Reader, IncompleteMultilineComment) { #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp index c8f4587..4407c25 100644 --- a/test/unittest/simdtest.cpp +++ b/test/unittest/simdtest.cpp @@ -41,7 +41,7 @@ using namespace rapidjson_simd; template void TestSkipWhitespace() { - for (int step = 1; step < 32; step++) { + for (size_t step = 1; step < 32; step++) { char buffer[1025]; for (size_t i = 0; i < 1024; i++) buffer[i] = " \t\r\n"[i % 4]; diff --git a/test/unittest/strtodtest.cpp b/test/unittest/strtodtest.cpp index dc2378b..1931653 100644 --- a/test/unittest/strtodtest.cpp +++ b/test/unittest/strtodtest.cpp @@ -99,13 +99,13 @@ TEST(Strtod, CheckApproximationCase) { EXPECT_EQ(49, hS_Exp5); BigInteger dS = BIGINTEGER_LITERAL(dInt); - dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); BigInteger bS(bInt); - bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2; + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); BigInteger hS(1); - hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS); EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS); diff --git a/test/unittest/unittest.cpp b/test/unittest/unittest.cpp index 4e3bc11..dd562a2 100644 --- a/test/unittest/unittest.cpp +++ b/test/unittest/unittest.cpp @@ -15,12 +15,14 @@ #include "unittest.h" #include "rapidjson/rapidjson.h" +AssertException::~AssertException() throw() {} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl; -#if _MSC_VER +#ifdef _MSC_VER _CrtMemState memoryState = { 0 }; _CrtMemCheckpoint(&memoryState); //_CrtSetBreakAlloc(X); @@ -29,7 +31,7 @@ int main(int argc, char **argv) { int ret = RUN_ALL_TESTS(); -#if _MSC_VER +#ifdef _MSC_VER // Current gtest constantly leak 2 blocks at exit _CrtMemDumpAllObjectsSince(&memoryState); #endif diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index dbba754..2aaa8cd 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -15,10 +15,18 @@ #ifndef UNITTEST_H_ #define UNITTEST_H_ - // gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS. #ifndef __STDC_CONSTANT_MACROS +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreserved-id-macro" +#endif + # define __STDC_CONSTANT_MACROS 1 // required by C++ standard + +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif #endif #ifdef _MSC_VER @@ -41,6 +49,11 @@ #pragma GCC diagnostic pop #endif +#ifdef __clang__ +// All TEST() macro generated this warning, disable globally +#pragma GCC diagnostic ignored "-Wglobal-constructors" +#endif + template inline unsigned StrLen(const Ch* s) { const Ch* p = s; @@ -51,19 +64,19 @@ inline unsigned StrLen(const Ch* s) { template inline int StrCmp(const Ch* s1, const Ch* s2) { while(*s1 && (*s1 == *s2)) { s1++; s2++; } - return (unsigned)*s1 < (unsigned)*s2 ? -1 : (unsigned)*s1 > (unsigned)*s2; + return static_cast(*s1) < static_cast(*s2) ? -1 : static_cast(*s1) > static_cast(*s2); } template inline Ch* StrDup(const Ch* str) { size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1); - Ch* buffer = (Ch*)malloc(bufferSize); + Ch* buffer = static_cast(malloc(bufferSize)); memcpy(buffer, str, bufferSize); return buffer; } inline FILE* TempFile(char *filename) { -#if _MSC_VER +#ifdef _MSC_VER filename = tmpnam(filename); // For Visual Studio, tmpnam() adds a backslash in front. Remove it. @@ -80,13 +93,14 @@ inline FILE* TempFile(char *filename) { } // Use exception for catching assert -#if _MSC_VER +#ifdef _MSC_VER #pragma warning(disable : 4127) #endif class AssertException : public std::logic_error { public: AssertException(const char* w) : std::logic_error(w) {} + virtual ~AssertException() throw(); }; #define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x)) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 900783c..1ef877e 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -448,7 +448,7 @@ TEST(Value, Uint) { TEST(Value, Int64) { // Constructor with int - Value x(int64_t(1234LL)); + Value x(int64_t(1234)); EXPECT_EQ(kNumberType, x.GetType()); EXPECT_EQ(1234, x.GetInt()); EXPECT_EQ(1234u, x.GetUint()); @@ -469,7 +469,7 @@ TEST(Value, Int64) { EXPECT_FALSE(x.IsObject()); EXPECT_FALSE(x.IsArray()); - Value nx(int64_t(-1234LL)); + Value nx(int64_t(-1234)); EXPECT_EQ(-1234, nx.GetInt()); EXPECT_EQ(-1234, nx.GetInt64()); EXPECT_TRUE(nx.IsInt()); @@ -482,17 +482,17 @@ TEST(Value, Int64) { z.SetInt64(1234); EXPECT_EQ(1234, z.GetInt64()); - z.SetInt64(2147483648LL); // 2^31, cannot cast as int + z.SetInt64(2147483648); // 2^31, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsUint()); EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0); - z.SetInt64(4294967296LL); // 2^32, cannot cast as uint + z.SetInt64(4294967296); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0); - z.SetInt64(-2147483649LL); // -2^31-1, cannot cast as int + z.SetInt64(int64_t(-2147483648) - 1); // -2^31-1, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); @@ -502,7 +502,7 @@ TEST(Value, Int64) { TEST(Value, Uint64) { // Constructor with int - Value x(uint64_t(1234LL)); + Value x(uint64_t(1234)); EXPECT_EQ(kNumberType, x.GetType()); EXPECT_EQ(1234, x.GetInt()); EXPECT_EQ(1234u, x.GetUint()); @@ -528,19 +528,19 @@ TEST(Value, Uint64) { z.SetUint64(1234); EXPECT_EQ(1234u, z.GetUint64()); - z.SetUint64(2147483648LL); // 2^31, cannot cast as int + z.SetUint64(uint64_t(2147483648)); // 2^31, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsUint()); EXPECT_TRUE(z.IsInt64()); - z.SetUint64(4294967296LL); // 2^32, cannot cast as uint + z.SetUint64(uint64_t(4294967295) + 1); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); EXPECT_TRUE(z.IsInt64()); - z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64 + z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64 EXPECT_FALSE(z.IsInt64()); - EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); // Issue 48 + EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48 EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble()); } @@ -662,7 +662,7 @@ TEST(Value, String) { // SetString() char s[] = "World"; Value w; - w.SetString(s, (SizeType)strlen(s), allocator); + w.SetString(s, static_cast(strlen(s)), allocator); s[0] = '\0'; EXPECT_STREQ("World", w.GetString()); EXPECT_EQ(5u, w.GetStringLength()); @@ -841,23 +841,23 @@ TEST(Value, Array) { EXPECT_EQ(x.Begin(), itr); EXPECT_EQ(9u, x.Size()); for (int i = 0; i < 9; i++) - EXPECT_EQ(i + 1, x[i][0].GetInt()); + EXPECT_EQ(i + 1, x[static_cast(i)][0].GetInt()); // Ease the last itr = x.Erase(x.End() - 1); EXPECT_EQ(x.End(), itr); EXPECT_EQ(8u, x.Size()); for (int i = 0; i < 8; i++) - EXPECT_EQ(i + 1, x[i][0].GetInt()); + EXPECT_EQ(i + 1, x[static_cast(i)][0].GetInt()); // Erase the middle itr = x.Erase(x.Begin() + 4); EXPECT_EQ(x.Begin() + 4, itr); EXPECT_EQ(7u, x.Size()); for (int i = 0; i < 4; i++) - EXPECT_EQ(i + 1, x[i][0].GetInt()); + EXPECT_EQ(i + 1, x[static_cast(i)][0].GetInt()); for (int i = 4; i < 7; i++) - EXPECT_EQ(i + 2, x[i][0].GetInt()); + EXPECT_EQ(i + 2, x[static_cast(i)][0].GetInt()); // Erase(ValueIterator, ValueIterator) // Exhaustive test with all 0 <= first < n, first <= last <= n cases @@ -879,7 +879,7 @@ TEST(Value, Array) { for (unsigned i = 0; i < first; i++) EXPECT_EQ(i, x[i][0].GetUint()); for (unsigned i = first; i < n - removeCount; i++) - EXPECT_EQ(i + removeCount, x[i][0].GetUint()); + EXPECT_EQ(i + removeCount, x[static_cast(i)][0].GetUint()); } } @@ -896,7 +896,7 @@ TEST(Value, Array) { x.Erase(std::remove(x.Begin(), x.End(), null), x.End()); EXPECT_EQ(5u, x.Size()); for (int i = 0; i < 5; i++) - EXPECT_EQ(i * 2, x[i]); + EXPECT_EQ(i * 2, x[static_cast(i)]); // SetArray() Value z; @@ -935,8 +935,8 @@ TEST(Value, Object) { o.AddMember("false", false, allocator); o.AddMember("int", -1, allocator); o.AddMember("uint", 1u, allocator); - o.AddMember("int64", INT64_C(-4294967296), allocator); - o.AddMember("uint64", UINT64_C(4294967296), allocator); + o.AddMember("int64", int64_t(-4294967296), allocator); + o.AddMember("uint64", uint64_t(4294967296), allocator); o.AddMember("double", 3.14, allocator); o.AddMember("string", "Jelly", allocator); @@ -944,8 +944,8 @@ TEST(Value, Object) { EXPECT_FALSE(o["false"].GetBool()); EXPECT_EQ(-1, o["int"].GetInt()); EXPECT_EQ(1u, o["uint"].GetUint()); - EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64()); - EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64()); + EXPECT_EQ(int64_t(-4294967296), o["int64"].GetInt64()); + EXPECT_EQ(uint64_t(4294967296), o["uint64"].GetUint64()); EXPECT_STREQ("Jelly",o["string"].GetString()); EXPECT_EQ(8u, o.MemberCount()); } @@ -1125,7 +1125,7 @@ TEST(Value, Object) { EXPECT_EQ(x.MemberBegin(), itr); EXPECT_EQ(9u, x.MemberCount()); for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()) + 1; + size_t i = static_cast((itr - x.MemberBegin())) + 1; EXPECT_STREQ(itr->name.GetString(), keys[i]); EXPECT_EQ(i, itr->value[0].GetInt()); } @@ -1136,7 +1136,7 @@ TEST(Value, Object) { EXPECT_EQ(x.MemberEnd(), itr); EXPECT_EQ(8u, x.MemberCount()); for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()) + 1; + size_t i = static_cast(itr - x.MemberBegin()) + 1; EXPECT_STREQ(itr->name.GetString(), keys[i]); EXPECT_EQ(i, itr->value[0].GetInt()); } @@ -1147,8 +1147,8 @@ TEST(Value, Object) { EXPECT_EQ(x.MemberBegin() + 4, itr); EXPECT_EQ(7u, x.MemberCount()); for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()); - i += (i<4) ? 1 : 2; + size_t i = static_cast(itr - x.MemberBegin()); + i += (i < 4) ? 1 : 2; EXPECT_STREQ(itr->name.GetString(), keys[i]); EXPECT_EQ(i, itr->value[0].GetInt()); } @@ -1214,7 +1214,7 @@ TEST(Value, BigNestedArray) { for (SizeType i = 0; i < n; i++) { Value y(kArrayType); for (SizeType j = 0; j < n; j++) { - Value number((int)(i * n + j)); + Value number(static_cast(i * n + j)); y.PushBack(number, allocator); } x.PushBack(y, allocator); @@ -1223,7 +1223,7 @@ TEST(Value, BigNestedArray) { for (SizeType i = 0; i < n; i++) for (SizeType j = 0; j < n; j++) { EXPECT_TRUE(x[i][j].IsInt()); - EXPECT_EQ((int)(i * n + j), x[i][j].GetInt()); + EXPECT_EQ(static_cast(i * n + j), x[i][j].GetInt()); } } @@ -1237,16 +1237,16 @@ TEST(Value, BigNestedObject) { sprintf(name1, "%d", i); // Value name(name1); // should not compile - Value name(name1, (SizeType)strlen(name1), allocator); + Value name(name1, static_cast(strlen(name1)), allocator); Value object(kObjectType); for (SizeType j = 0; j < n; j++) { char name2[10]; sprintf(name2, "%d", j); - Value name(name2, (SizeType)strlen(name2), allocator); - Value number((int)(i * n + j)); - object.AddMember(name, number, allocator); + Value name3(name2, static_cast(strlen(name2)), allocator); + Value number(static_cast(i * n + j)); + object.AddMember(name3, number, allocator); } // x.AddMember(name1, object, allocator); // should not compile @@ -1261,7 +1261,7 @@ TEST(Value, BigNestedObject) { char name2[10]; sprintf(name2, "%d", j); x[name1]; - EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt()); + EXPECT_EQ(static_cast(i * n + j), x[name1][name2].GetInt()); } } } @@ -1293,7 +1293,7 @@ TEST(Document, CrtAllocator) { } static void TestShortStringOptimization(const char* str) { - const rapidjson::SizeType len = (rapidjson::SizeType)strlen(str); + const rapidjson::SizeType len = static_cast(strlen(str)); rapidjson::Document doc; rapidjson::Value val; From 17f2ca6913c60618196e2e93d36100dc237c60db Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:04:09 +0800 Subject: [PATCH 37/98] Try to fix clang and gcc warnings problems --- include/rapidjson/document.h | 10 +++------- include/rapidjson/reader.h | 13 +++---------- test/unittest/unittest.h | 2 ++ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 8fde16c..dc40239 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -30,6 +30,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef __GNUC__ @@ -724,9 +725,7 @@ public: else return data_.n.u64 == rhs.data_.n.u64; - case kNullType: - case kFalseType: - case kTrueType: + default: return true; } } @@ -2106,10 +2105,7 @@ GenericValue::GenericValue(const GenericValue(&rhs.data_); break; diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 4cb7d50..b704154 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -42,6 +42,7 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef __GNUC__ @@ -1417,9 +1418,7 @@ private: } } - case IterativeParsingStartState: - case IterativeParsingFinishState: - case IterativeParsingValueState: + default: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. @@ -1456,13 +1455,7 @@ private: case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; - case IterativeParsingErrorState: - case IterativeParsingKeyValueDelimiterState: - case IterativeParsingObjectFinishState: - case IterativeParsingArrayInitialState: - case IterativeParsingElementDelimiterState: - case IterativeParsingArrayFinishState: - case IterativeParsingValueState: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; + default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; } } diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 2aaa8cd..6062410 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -19,8 +19,10 @@ #ifndef __STDC_CONSTANT_MACROS #ifdef __clang__ #pragma GCC diagnostic push +#if __has_warning("-Wreserved-id-macro") #pragma GCC diagnostic ignored "-Wreserved-id-macro" #endif +#endif # define __STDC_CONSTANT_MACROS 1 // required by C++ standard From 9ce381b80165095b79f7ab3475a4a544cde73f4e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:15:51 +0800 Subject: [PATCH 38/98] Try to fix clang and gcc warnings problems again --- example/messagereader/messagereader.cpp | 16 ++++++++++++---- include/rapidjson/document.h | 3 ++- include/rapidjson/error/en.h | 13 ++++++++++++- include/rapidjson/filereadstream.h | 1 + include/rapidjson/filewritestream.h | 9 +++++++++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/example/messagereader/messagereader.cpp b/example/messagereader/messagereader.cpp index d19292b..3399bc9 100644 --- a/example/messagereader/messagereader.cpp +++ b/example/messagereader/messagereader.cpp @@ -17,6 +17,11 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + struct MessageHandler : public BaseReaderHandler, MessageHandler> { MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {} @@ -26,16 +31,13 @@ struct MessageHandler case kExpectObjectStart: state_ = kExpectNameOrObjectEnd; return true; - case kExpectNameOrObjectEnd: - case kExpectValue: + default: return false; } } bool String(const char* str, SizeType length, bool) { switch (state_) { - case kExpectObjectStart: - return false; case kExpectNameOrObjectEnd: name_ = string(str, length); state_ = kExpectValue; @@ -44,6 +46,8 @@ struct MessageHandler messages_.insert(MessageMap::value_type(name_, string(str, length))); state_ = kExpectNameOrObjectEnd; return true; + default: + return false; } } @@ -64,6 +68,10 @@ struct MessageHandler RAPIDJSON_DIAG_POP #endif +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + static void ParseMessages(const char* json, MessageMap& messages) { Reader reader; MessageHandler handler; diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index dc40239..3838af9 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1557,7 +1557,8 @@ public: case kStringType: return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); - case kNumberType: + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h index 81932e2..c2315fd 100644 --- a/include/rapidjson/error/en.h +++ b/include/rapidjson/error/en.h @@ -17,6 +17,12 @@ #include "error.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. @@ -54,10 +60,15 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); } - return RAPIDJSON_ERROR_STRING("Unknown error."); } RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_ERROR_EN_H_ diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index 588f7f1..b6d6524 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -21,6 +21,7 @@ #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) #endif RAPIDJSON_NAMESPACE_BEGIN diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 55da265..3c38329 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -18,6 +18,11 @@ #include "rapidjson.h" #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for input using fread(). @@ -92,4 +97,8 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_FILESTREAM_H_ From a6a73b51b5753866f513b029fa721081521c1a9e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:36:51 +0800 Subject: [PATCH 39/98] Try to fix clang and gcc warnings problems againx2 --- include/rapidjson/memorystream.h | 9 +++++++++ include/rapidjson/pointer.h | 31 ++++++++++++++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h index 03c04e8..dfaec37 100644 --- a/include/rapidjson/memorystream.h +++ b/include/rapidjson/memorystream.h @@ -17,6 +17,11 @@ #include "rapidjson.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. @@ -58,4 +63,8 @@ struct MemoryStream { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index f58ce35..7519490 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -18,6 +18,11 @@ #include "document.h" #include "internal/itoa.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token @@ -71,7 +76,7 @@ template class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value - typedef typename EncodingType::Ch Ch; //!< Character type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! @@ -472,11 +477,7 @@ public: return 0; v = &((*v)[t->index]); break; - case kNullType: - case kFalseType: - case kTrueType: - case kStringType: - case kNumberType: + default: return 0; } } @@ -705,11 +706,7 @@ public: return false; v = &((*v)[t->index]); break; - case kNullType: - case kFalseType: - case kTrueType: - case kStringType: - case kNumberType: + default: return false; } } @@ -722,11 +719,7 @@ public: return false; v->Erase(v->Begin() + last->index); return true; - case kNullType: - case kFalseType: - case kTrueType: - case kStringType: - case kNumberType: + default: return false; } } @@ -958,7 +951,7 @@ private: */ class PercentDecodeStream { public: - typedef Ch Ch; + typedef typename ValueType::Ch Ch; //! Constructor /*! @@ -1326,4 +1319,8 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_POINTER_H_ From 4cb7c88ca901d4cca62675452ca2b1437702e1ec Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:47:11 +0800 Subject: [PATCH 40/98] Try to fix clang and gcc warnings problems again x3 --- test/unittest/readertest.cpp | 4 ++-- test/unittest/strtodtest.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 056ccb4..6285181 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -164,12 +164,12 @@ TEST(Reader, ParseNumber_Integer) { u.u |= r(); char buffer[32]; - if (u.u > 4294967295) { + if (u.u > uint64_t(4294967295u)) { *internal::u64toa(u.u, buffer) = '\0'; TEST_INTEGER(ParseUint64Handler, buffer, u.u); } - if (u.i < -2147483648) { + if (u.i < -int64_t(2147483648u)) { *internal::i64toa(u.i, buffer) = '\0'; TEST_INTEGER(ParseInt64Handler, buffer, u.i); } diff --git a/test/unittest/strtodtest.cpp b/test/unittest/strtodtest.cpp index 1931653..a42d96e 100644 --- a/test/unittest/strtodtest.cpp +++ b/test/unittest/strtodtest.cpp @@ -16,6 +16,11 @@ #include "rapidjson/internal/strtod.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + #define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1) using namespace rapidjson::internal; @@ -121,3 +126,7 @@ TEST(Strtod, CheckApproximationCase) { EXPECT_EQ(-1, delta.Compare(hS)); } + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif From d6478991d078eee2c0a48bca493810e6adf81ab6 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:54:10 +0800 Subject: [PATCH 41/98] Try to fix clang and gcc warnings problems again x4 --- include/rapidjson/filereadstream.h | 4 ++-- test/unittest/readertest.cpp | 4 ++-- test/unittest/valuetest.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index b6d6524..a31d7c0 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -51,8 +51,8 @@ public: size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } - void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 6285181..3248a5d 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1040,8 +1040,8 @@ public: size_t Tell() const { return static_cast(is_.tellg()); } Ch* PutBegin() { assert(false); return 0; } - void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { assert(false); } - void Flush() RAPIDJSON_NORETURN_SUFFIX { assert(false); } + void Put(Ch) { assert(false); } + void Flush() { assert(false); } size_t PutEnd(Ch*) { assert(false); return 0; } private: diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 1ef877e..cac450c 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -482,12 +482,12 @@ TEST(Value, Int64) { z.SetInt64(1234); EXPECT_EQ(1234, z.GetInt64()); - z.SetInt64(2147483648); // 2^31, cannot cast as int + z.SetInt64(2147483648u); // 2^31, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsUint()); EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0); - z.SetInt64(4294967296); // 2^32, cannot cast as uint + z.SetInt64(int64_t(4294967298u) + 1); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0); @@ -528,12 +528,12 @@ TEST(Value, Uint64) { z.SetUint64(1234); EXPECT_EQ(1234u, z.GetUint64()); - z.SetUint64(uint64_t(2147483648)); // 2^31, cannot cast as int + z.SetUint64(uint64_t(2147483648u)); // 2^31, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsUint()); EXPECT_TRUE(z.IsInt64()); - z.SetUint64(uint64_t(4294967295) + 1); // 2^32, cannot cast as uint + z.SetUint64(uint64_t(4294967295u) + 1); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); EXPECT_TRUE(z.IsInt64()); From 6e08e760fc2ab9a91c2a0e56b49c4fa16b036375 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 19:57:43 +0800 Subject: [PATCH 42/98] Try to fix clang and gcc warnings problems again x5 --- include/rapidjson/filereadstream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index a31d7c0..b6d6524 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -51,8 +51,8 @@ public: size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } + void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } From d72039f3ef30ec2e63955d5159d87f5ac255cf21 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:06:58 +0800 Subject: [PATCH 43/98] Try to fix clang and gcc warnings problems again x6 --- test/unittest/readertest.cpp | 4 ++-- test/unittest/valuetest.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 3248a5d..6285181 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1040,8 +1040,8 @@ public: size_t Tell() const { return static_cast(is_.tellg()); } Ch* PutBegin() { assert(false); return 0; } - void Put(Ch) { assert(false); } - void Flush() { assert(false); } + void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { assert(false); } + void Flush() RAPIDJSON_NORETURN_SUFFIX { assert(false); } size_t PutEnd(Ch*) { assert(false); return 0; } private: diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index cac450c..4e08e54 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -487,7 +487,7 @@ TEST(Value, Int64) { EXPECT_TRUE(z.IsUint()); EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0); - z.SetInt64(int64_t(4294967298u) + 1); // 2^32, cannot cast as uint + z.SetInt64(int64_t(4294967295u) + 1); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0); From 6d6381f596f081097d123b24a2091ae4c29bef39 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:15:11 +0800 Subject: [PATCH 44/98] Try to fix clang and gcc warnings problems again x7 --- include/rapidjson/document.h | 4 ++-- include/rapidjson/rapidjson.h | 2 +- test/unittest/valuetest.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3838af9..095aa40 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1231,7 +1231,7 @@ public: for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= (last - first); + data_.o.size -= static_cast(last - first); return pos; } @@ -1431,7 +1431,7 @@ public: for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); - data_.a.size -= (last - first); + data_.a.size -= static_cast(last - first); return pos; } diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 41790cf..e3560b7 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -467,7 +467,7 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NORETURN_SUFFIX -#if defined(__clang__) +#if defined(__clang__) && !defined(NDEBUG) #define RAPIDJSON_NORETURN_SUFFIX __attribute__ ((noreturn)) #else #define RAPIDJSON_NORETURN_SUFFIX diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 4e08e54..8d0f762 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -492,7 +492,7 @@ TEST(Value, Int64) { EXPECT_FALSE(z.IsUint()); EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0); - z.SetInt64(int64_t(-2147483648) - 1); // -2^31-1, cannot cast as int + z.SetInt64(-int64_t(2147483648u) - 1); // -2^31-1, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); From efdbdc601607759702790d1be0a69005eaf5e3b8 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:26:34 +0800 Subject: [PATCH 45/98] Try to fix clang and gcc warnings problems again x8 --- include/rapidjson/reader.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index b704154..107f525 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -306,7 +306,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; @@ -320,18 +320,18 @@ inline const char *SkipWhitespace_SIMD(const char* p) { "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; - const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); for (;; p += 16) { - const __m128i s = _mm_load_si128((const __m128i *)p); + const __m128i s = _mm_load_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; From 5c003f3ecb8c00d9ed7f8da16469e17cf1d82d8f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:34:46 +0800 Subject: [PATCH 46/98] Try to fix clang and gcc warnings problems again x9 Abandon RAPIDJSON_NORETURN_SUFFIX --- include/rapidjson/filereadstream.h | 5 +++-- include/rapidjson/memorystream.h | 5 +++-- include/rapidjson/rapidjson.h | 9 --------- test/unittest/readertest.cpp | 5 +++-- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index b6d6524..6c8a86c 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -22,6 +22,7 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN @@ -51,8 +52,8 @@ public: size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } - void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h index dfaec37..beed1ef 100644 --- a/include/rapidjson/memorystream.h +++ b/include/rapidjson/memorystream.h @@ -20,6 +20,7 @@ #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN @@ -46,8 +47,8 @@ struct MemoryStream { size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } - void Flush() RAPIDJSON_NORETURN_SUFFIX { RAPIDJSON_ASSERT(false); } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index e3560b7..d896a14 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -464,15 +464,6 @@ RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIAG_* -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_NORETURN_SUFFIX - -#if defined(__clang__) && !defined(NDEBUG) -#define RAPIDJSON_NORETURN_SUFFIX __attribute__ ((noreturn)) -#else -#define RAPIDJSON_NORETURN_SUFFIX -#endif - /////////////////////////////////////////////////////////////////////////////// // C++11 features diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 6285181..f2a0be1 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -25,6 +25,7 @@ using namespace rapidjson; RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(float-equal) +RAPIDJSON_DIAG_OFF(missing-noreturn) #endif #ifdef __clang__ @@ -1040,8 +1041,8 @@ public: size_t Tell() const { return static_cast(is_.tellg()); } Ch* PutBegin() { assert(false); return 0; } - void Put(Ch) RAPIDJSON_NORETURN_SUFFIX { assert(false); } - void Flush() RAPIDJSON_NORETURN_SUFFIX { assert(false); } + void Put(Ch) { assert(false); } + void Flush() { assert(false); } size_t PutEnd(Ch*) { assert(false); return 0; } private: From 81c07721cbace6eee545d35d4bf9da30353092dc Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:38:08 +0800 Subject: [PATCH 47/98] Try to fix clang and gcc warnings problems again x10 --- include/rapidjson/reader.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 107f525..8628b53 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -321,9 +321,9 @@ inline const char *SkipWhitespace_SIMD(const char* p) { "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); - const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); - const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); From c6384da75530996d07af6f0896c33e8fd973f319 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 18 Dec 2015 20:53:07 +0800 Subject: [PATCH 48/98] Try to fix clang and gcc warnings problems again x11 --- test/unittest/valuetest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 8d0f762..245ccac 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1162,11 +1162,11 @@ TEST(Value, Object) { for (unsigned i = 0; i < n; i++) x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); - itr = x.EraseMember(x.MemberBegin() + first, x.MemberBegin() + last); + itr = x.EraseMember(x.MemberBegin() + static_cast(first), x.MemberBegin() + static_cast(last)); if (last == n) EXPECT_EQ(x.MemberEnd(), itr); else - EXPECT_EQ(x.MemberBegin() + first, itr); + EXPECT_EQ(x.MemberBegin() + static_cast(first), itr); size_t removeCount = last - first; EXPECT_EQ(n - removeCount, x.MemberCount()); From 5121034bb803023b8164dfcfec0e82d05a6530f6 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Tue, 29 Dec 2015 15:24:13 +0200 Subject: [PATCH 49/98] CMake will no longer complain that the minimum CMake version is not specified for test/CMakeLists.txt. --- test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c698af4..4af75bd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,5 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + find_package(GTestSrc) IF(GTESTSRC_FOUND) From caa4d22d1680f22e26c07f3a2c47354f121479da Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Tue, 29 Dec 2015 18:15:52 +0200 Subject: [PATCH 50/98] Initial attempt at moving travis to containerized infrastructure. --- .travis.yml | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index be06f35..0f7cfc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ language: cpp - +sudo: false +cache: + - ccache compiler: - clang - gcc +addons: {apt: {packages: &default_packages [cmake, valgrind, doxygen]}} env: matrix: - CONF=debug ARCH=x86_64 @@ -11,31 +14,35 @@ env: - CONF=debug ARCH=x86 - CONF=release ARCH=x86 global: + - USE_CCACHE=1 + - CCACHE_SLOPPINESS=pch_defines,time_macros + - CCACHE_COMPRESS=1 + - CCACHE_MAXSIZE=100M - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit - GITHUB_REPO='miloyip/rapidjson' - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" -before_install: - - sudo apt-get update -qq - - sudo apt-get install -qq cmake valgrind - - sudo apt-get --no-install-recommends install doxygen # Don't install LaTeX stuffs - - if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi - - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi - -install: true +matrix: + include: + env: CONF=debug ARCH=x86 + addons: {apt: {packages: [*default_packages, g++-multilib, libc6-dbg:i386]}} + include: + env: CONF=release ARCH=x86 + addons: {apt: {packages: [*default_packages, g++-multilib, libc6-dbg:i386]}} before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), # exposed by merging PR#163 (using -march=native) + - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then export GCOV_FLAGS='--coverage'; fi - sed -i "s/-march=native//" CMakeLists.txt - - mkdir build + - mkdir build - > eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; - (cd build && cmake + (cd build && cmake -DRAPIDJSON_HAS_STDSTRING=ON - -DCMAKE_VERBOSE_MAKEFILE=ON - -DCMAKE_BUILD_TYPE=$CONF + -DCMAKE_VERBOSE_MAKEFILE=ON + -DCMAKE_BUILD_TYPE=$CONF -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS" -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS ..) @@ -48,4 +55,5 @@ script: - make travis_doc after_success: - - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h + - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then pip install --user cpp-coveralls; fi + - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h; fi From feadfad2660cd5cc332f99b14bb3ec78bb3d02d3 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 12:18:39 +0200 Subject: [PATCH 51/98] Fix syntax errors. --- .travis.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f7cfc0..a0feeb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,13 @@ compiler: - clang - gcc -addons: {apt: {packages: &default_packages [cmake, valgrind, doxygen]}} +addons: + apt: + packages: &default_packages + - cmake + - valgrind + - doxygen + env: matrix: - CONF=debug ARCH=x86_64 @@ -26,10 +32,20 @@ env: matrix: include: env: CONF=debug ARCH=x86 - addons: {apt: {packages: [*default_packages, g++-multilib, libc6-dbg:i386]}} + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 include: env: CONF=release ARCH=x86 - addons: {apt: {packages: [*default_packages, g++-multilib, libc6-dbg:i386]}} + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), From 6d97d8bf7166afddbdb650bd0414d02b68432814 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 12:32:26 +0200 Subject: [PATCH 52/98] Fixed bash syntax error. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0feeb7..3b3b91f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,4 +72,4 @@ script: after_success: - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then pip install --user cpp-coveralls; fi - - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h; fi + - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h; fi From 4fadfa5c223a8ea7fadd53cce228319f55cb6aea Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 13:06:53 +0200 Subject: [PATCH 53/98] Corrected the build matrix and removed inline logic. --- .travis.yml | 66 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3b3b91f..a52ac2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,26 +31,51 @@ env: matrix: include: - env: CONF=debug ARCH=x86 - addons: - apt: - packages: - - *default_packages - - g++-multilib - - libc6-dbg:i386 - include: - env: CONF=release ARCH=x86 - addons: - apt: - packages: - - *default_packages - - g++-multilib - - libc6-dbg:i386 + - env: CONF=debug ARCH=x86 + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + - env: CONF=release ARCH=x86 + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' + compiler: gcc + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + after_success: + - ./travis-coveralls.sh + - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' + compiler: gcc + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + after_success: + - ./travis-coveralls.sh + # These jobs report code coverage so they need extra environment variables + # and commands + exclude: + - env: CONF=debug ARCH=x86_64 + compiler: gcc + - env: CONF=debug ARCH=x86 + compiler: gcc before_script: -# hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), -# exposed by merging PR#163 (using -march=native) - - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then export GCOV_FLAGS='--coverage'; fi + # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), + # exposed by merging PR#163 (using -march=native) - sed -i "s/-march=native//" CMakeLists.txt - mkdir build - > @@ -69,7 +94,4 @@ script: - make examples - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"` - make travis_doc - -after_success: - - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then pip install --user cpp-coveralls; fi - - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h; fi + From 6400ab8d18cf115f67698f7014c3d2bb9bad6979 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 13:10:39 +0200 Subject: [PATCH 54/98] Added the missing coveralls script. --- travis-coveralls.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 travis-coveralls.sh diff --git a/travis-coveralls.sh b/travis-coveralls.sh new file mode 100755 index 0000000..7825265 --- /dev/null +++ b/travis-coveralls.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +pip install --user cpp-coveralls +coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h From 2a7836c96119f0f6a248845753b440561389d2b2 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 13:11:39 +0200 Subject: [PATCH 55/98] Cached python packages as well for faster coverage reporting. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a52ac2d..7cabb6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: cpp sudo: false cache: - ccache + - pip compiler: - clang - gcc @@ -94,4 +95,3 @@ script: - make examples - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"` - make travis_doc - From 291bcf94b0245af34608e92eb2e32524da9f9e54 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:01:44 +0200 Subject: [PATCH 56/98] Fixed path to coverage script. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7cabb6e..4aae68c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ matrix: - g++-multilib - libc6-dbg:i386 after_success: - - ./travis-coveralls.sh + - ../travis-coveralls.sh - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' compiler: gcc addons: @@ -65,7 +65,7 @@ matrix: - g++-multilib - libc6-dbg:i386 after_success: - - ./travis-coveralls.sh + - ../travis-coveralls.sh # These jobs report code coverage so they need extra environment variables # and commands exclude: From 1f43a6f0b2b743a8e031d1e88bc77204665e4300 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:07:32 +0200 Subject: [PATCH 57/98] Added comment. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4aae68c..179b4cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,7 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 + # coverage report - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' compiler: gcc addons: From 3a01a252425c1b80cac0b730060c5185a1a31ce5 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:09:36 +0200 Subject: [PATCH 58/98] Explictly specify compiler in the matrix. --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.travis.yml b/.travis.yml index 179b4cb..fe7f617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,15 @@ env: matrix: include: - env: CONF=debug ARCH=x86 + compiler: gcc + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + - env: CONF=debug ARCH=x86 + compiler: clang addons: apt: packages: @@ -40,6 +49,15 @@ matrix: - g++-multilib - libc6-dbg:i386 - env: CONF=release ARCH=x86 + compiler: gcc + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + - env: CONF=release ARCH=x86 + compiler: clang addons: apt: packages: From c3cd3edad2dd78eabc1d48ec7ab052614c468db2 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:52:11 +0200 Subject: [PATCH 59/98] Explictly specify the entire matrix. --- .travis.yml | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe7f617..bced68d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,6 @@ sudo: false cache: - ccache - pip -compiler: - - clang - - gcc addons: apt: @@ -15,11 +12,6 @@ addons: - doxygen env: - matrix: - - CONF=debug ARCH=x86_64 - - CONF=release ARCH=x86_64 - - CONF=debug ARCH=x86 - - CONF=release ARCH=x86 global: - USE_CCACHE=1 - CCACHE_SLOPPINESS=pch_defines,time_macros @@ -32,22 +24,6 @@ env: matrix: include: - - env: CONF=debug ARCH=x86 - compiler: gcc - addons: - apt: - packages: - - *default_packages - - g++-multilib - - libc6-dbg:i386 - - env: CONF=debug ARCH=x86 - compiler: clang - addons: - apt: - packages: - - *default_packages - - g++-multilib - - libc6-dbg:i386 - env: CONF=release ARCH=x86 compiler: gcc addons: @@ -56,6 +32,18 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 + - env: CONF=release ARCH=x86_64 + compiler: gcc + - env: CONF=debug ARCH=x86 + compiler: clang + addons: + apt: + packages: + - *default_packages + - g++-multilib + - libc6-dbg:i386 + - env: CONF=debug ARCH=x86_64 + compiler: clang - env: CONF=release ARCH=x86 compiler: clang addons: @@ -64,6 +52,8 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 + - env: CONF=release ARCH=x86_64 + compiler: clang # coverage report - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' compiler: gcc @@ -85,13 +75,6 @@ matrix: - libc6-dbg:i386 after_success: - ../travis-coveralls.sh - # These jobs report code coverage so they need extra environment variables - # and commands - exclude: - - env: CONF=debug ARCH=x86_64 - compiler: gcc - - env: CONF=debug ARCH=x86 - compiler: gcc before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), From db11011a5c12e4efa0e27a915737f5af4765454c Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:55:24 +0200 Subject: [PATCH 60/98] Script seems to fail to report coverage. Explictly specifying the commands. --- .travis.yml | 6 ++++-- travis-coveralls.sh | 4 ---- 2 files changed, 4 insertions(+), 6 deletions(-) delete mode 100755 travis-coveralls.sh diff --git a/.travis.yml b/.travis.yml index bced68d..640c24d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,8 @@ matrix: - g++-multilib - libc6-dbg:i386 after_success: - - ../travis-coveralls.sh + - pip install --user cpp-coveralls + - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' compiler: gcc addons: @@ -74,7 +75,8 @@ matrix: - g++-multilib - libc6-dbg:i386 after_success: - - ../travis-coveralls.sh + - pip install --user cpp-coveralls + - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), diff --git a/travis-coveralls.sh b/travis-coveralls.sh deleted file mode 100755 index 7825265..0000000 --- a/travis-coveralls.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -pip install --user cpp-coveralls -coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h From 3186e31b579c2b2151a3a8d4c965969dd3d0b4e1 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Wed, 30 Dec 2015 15:57:44 +0200 Subject: [PATCH 61/98] Print cache statistics. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 640c24d..981ea37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,6 +81,7 @@ matrix: before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), # exposed by merging PR#163 (using -march=native) + - ccache -s - sed -i "s/-march=native//" CMakeLists.txt - mkdir build - > From ef6957c177bd6d971bfedfbfe656c4b82d71f9a3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 31 Dec 2015 15:30:28 +0800 Subject: [PATCH 62/98] PutReserve() and PutUnsafe() optimisation for Writer --- .gitignore | 1 + bin/types/booleans.json | Bin 0 -> 849 bytes bin/types/floats.json | Bin 0 -> 1698 bytes bin/types/guids.json | Bin 0 -> 4202 bytes bin/types/integers.json | Bin 0 -> 1098 bytes bin/types/mixed.json | Bin 0 -> 15142 bytes bin/types/nulls.json | Bin 0 -> 802 bytes bin/types/paragraphs.json | Bin 0 -> 33764 bytes bin/types/readme.txt | 1 + include/rapidjson/encodings.h | 77 +++++++++++++++++++ include/rapidjson/internal/stack.h | 12 ++- include/rapidjson/rapidjson.h | 16 +++- include/rapidjson/stringbuffer.h | 13 ++++ include/rapidjson/writer.h | 79 +++++++++++--------- test/perftest/perftest.h | 114 ++++++++++++++++++++--------- test/perftest/rapidjsontest.cpp | 29 +++++++- 16 files changed, 272 insertions(+), 70 deletions(-) create mode 100755 bin/types/booleans.json create mode 100755 bin/types/floats.json create mode 100755 bin/types/guids.json create mode 100755 bin/types/integers.json create mode 100755 bin/types/mixed.json create mode 100755 bin/types/nulls.json create mode 100755 bin/types/paragraphs.json create mode 100644 bin/types/readme.txt diff --git a/.gitignore b/.gitignore index d97a316..2c412c2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ !/bin/data !/bin/encodings !/bin/jsonchecker +!/bin/types /build /doc/html /doc/doxygen_*.db diff --git a/bin/types/booleans.json b/bin/types/booleans.json new file mode 100755 index 0000000000000000000000000000000000000000..2dcbb5fe8765a18916d8f6d517dd0e24d479c250 GIT binary patch literal 849 zcmcJJI|_g>5JdZ&A_wqBVqu|`m7n_y!W%RL30bh3$?V(Nj49`Hzn0;p>%1LLAX5^& z1;|7u9m`fvP^voJfNElaO(0sTMHw~}xB)>$5TG`&01_48rUNmQAgcbGO7g=IDg#%2 Ie;c+jrNsOx;^!tf0}ci_*lfvq1`LGr%U_> zoSa3H+4G91@0BGYd)G~(n#;shxa1dyN-eP*^OC+$tCv|QbzE;iPBY`<{mT3{b@#-S zP2L-`bfV2eZ!fi%dP^siobOI+u|)uP&p$QcMVgK2&F~{Ip&@kq0t!KuaA9p1*N-!N zRY=_=W-F}poF9RE7WKF6@b|!V!HkUc6X7?xq|J8aOQABWO!lvhG!Z5bu#uM~P**dl^wjlU;?tHk&xVNY5z<)XVXvS{ha6KJ>>$+` zSldrJ8+yZIk&oqLC}^|)MUX`?tfKNcj^4Ec4N7mx(ONDI|qY&lxtvYw2gTve~E5}HIVZ$&a^mEJGj1a+USPmM4kiyAKT(#avM#78igu- zFviv>dL`Vwl!}Yz4A5%lX&Schr#Zl$gaH?ww%hv_MPr9NfOa@($7vT?%yC-Vz zNap7TM3+iXmN9<;*s_heApJt;^V+)0aQ=G(b_TYyGG2G1tRpz~Z$Op09SnayR z(srGt=E~~~IbSF=*S#YceKlqtW9AUSg*z3iShIIv+lzo&z;o&}yaRNe?CD{WRK Z({KVx*$F6S%YS8$Mc5mPY5x5C=Rb9MGfe;h literal 0 HcmV?d00001 diff --git a/bin/types/guids.json b/bin/types/guids.json new file mode 100755 index 0000000000000000000000000000000000000000..9d7f5dbc8f9e0a8fcb6748412300c0c73b3e06c0 GIT binary patch literal 4202 zcmX|^NshEB4ug-!0L)G< zy7UCusRygG1Y5(;YQ5&x{`t?Jl`b*&E@5wPL0a)JhPE)J>J(Y()xMS4@|F}+@OpBP z=o+-w7gyC#vs;bP}Lb? z^XhBNJ=b{#J6cUEC~m zoAuUi!L*Ffe9W^o*WTn?>0*1PG(z=g+*4-oq8d^hn%Wf2_G;g8pE%t^%AJ*#H4LQ- zwM%lzqvrlrt{Ss8t6_Sl^KwL9yNF1DblFcA_uV8~G(EWqL!MzJ!d;3)i{C{ znkw58{Zz2jT0bDPw*C4!&1reeVa>IINR{Ae#L$+dEJJ!3ulB5Er8*|>o;Y1=3r;1W z#yWD%+bq46Nm{CXw$QV&GFDC>Bhj?Bt#v6&-#u-gb}|U*CBhD0nH!(Z>9xh`bF7fWMjSfN% zy^)?u7-z@8qSfM>I*xuT`&Re@!DA8Lh(f|BL&KzfvF$!ae|$fA`>A$9s}MuZ*}3CiABu zkfMOW9FpEQ8WYq}O{g||U&lEA?U{?xUk$}(T>8Xw=yGcWOnk^BTBmgk@J}Aay9+Y7Z6hI-tdm~+EZBH#^Q7W>G>Kz>+BMRWr zt`2^kx3~qQ$50$NOWKOaRMZu&pFM3)6amafNqX z=+2qcwL1!fay1wdp zNX{8W=$OG=8+k~ONh6)j%MW<+w({$IK1WNm5-MEhbVb1u?C`Y~9OP%beo~|Q2Abzw zolmz*!+MDQAPy}b`C&fqlwG9-_T_Y#$Q#j5lcF*JTG1fEJ3+rS- zs!{gy?ny5MORd)e=;soyDCS%{7n>6SJ3oZXD6P`;-7n^4&0vr>j9B{K=GN?Wsd?NZ zBG>cOyJtl@ts_ny!^ZrS$NFA#)nw)598hUc7ZrBca9(q7e0r( z;|J^RZSgruRDOJ)NYAECA$5dXF7))I9TKWnadPeX>8EUbb7s^Xjo`JfE+GJ6YD_#q zjVnHn>rE^E3_k5@NTf?6!A-@#212X$L$bCLfqO$gvCJDh(BxD3lRfyd(fhCVJngE_ zM7^Dr)gtKvWk5Y5xOGl{E7KS(MQyg#i^}UqhS=XEfb;-=dv54(6_vXsKy@+pRM*1k zC~Xr#UtSVG%K#RP>wh$P;q+tXNI!9%5+i2vYOkqyp?N^!>ij|#x#s0FF((ypz8^w} z8Yx}r!~$R(?}E#amyo*EZ@g*xFi&5q#=b+W1Ti@c9$gLDng7UH6M=XLahDn&i66hcG zUN+iHUK;7@=h_{~S6=&&Pv|FrL;DtL9qs(i;4gm9O>$$|yL z`0h!B-plz{aYvUXzdYhHB@LooYs>8+dGuw{QDOv+&J&2p^R$Z4ltibd^W)KI zxr2)Fcx>1m+JPl<++hHCNUlb`j{Wh@?0FhIVo^Yjn3ZDPJO7o+Ki&YznqZ(fptM4RrSdBxTr>gbz60;IDL2V`P&;00hWpY-5p z`gvSI`yvw?u1&BY1wjnFm06}W1EJ_gd`&yR{O^agwu^7!r2M!~QJm~ev}qWV)sWl$tZATRsokVO(5 zbulDuCL~6R#5;Ulf=7jZpmjt*R1pIi%o_-r@7!Vmiw~c~U|N$GU1U5ECq3w7ure6i zK>(0?d~Xak4i2x1*h+v+W$XLv<#yGK=Su=+8Y6tOzN`}@_ zsXa4ujnXNQOLd%|iT)*lK8VeKTsv=Ga|7o;ES46Hz_Iz{?P;VgmL6n~5K1^gBN*6_ m@XXlB=!1}brw=Owi$FQf)g{Qolk;b;Ae7Vy^5vhu{`Y@~_4(`o literal 0 HcmV?d00001 diff --git a/bin/types/integers.json b/bin/types/integers.json new file mode 100755 index 0000000000000000000000000000000000000000..5dd05e097a4f89220957e18bd013c58ab7e4b44f GIT binary patch literal 1098 zcmXw2$+25O2)zF&egHlI%^Hi#`KRF?kV*$pGrWdg=I_t%Z>vRi{(0p@m&_|;D$VSb z+B`RZWlgpZ_7qWmpQ*NM?7g(g)GIv^?B3Ie02a%v#IOKxYs8**&U|`Jx^NBEslb9& zguBZFGtm<0;!bPMBBb!w+pAqww+?K|Yd3Ecw6-BNI&E222htY|A{?>hWQfZuVoB<; zr(`LWTl#dnZ9|HqWy!ZB*IjO@0@EdL?G5a-rjj|!Vhj=28$&ofFx8}jk6U`FViADw zIL2OGu1je0aXv7&`0%mE=&YD5%y}7ZCzCqqo`1$`-D@LI#_2pl(Bo*8iI3~Vx`uu} zA47i=!dzBaDiPb9hGM=4XLbks?;d{*&f}P9bsxUat*Gcr;>&iRegGRH1Zmt zhEEuZ_A(@|A;iY>q-i(~0gMwfw+KT$FVT#X_@%`|TYW!!so+Mhmr3b3@#qd?w1k4U z9;+@Ad?}{`DcEVsf7*7EFmR320W`kuC1`QVe%4XpUsp8j3{*PJ{J$M?%3O|6wMBhw z0i(GM3<$$;xLiPQ8pBv}y#o*HOG7@lzH#c&1LG6syfgV5ob3(o3 literal 0 HcmV?d00001 diff --git a/bin/types/mixed.json b/bin/types/mixed.json new file mode 100755 index 0000000000000000000000000000000000000000..43e9a1d7be070f5eb75a3925f99a54b701b4c65b GIT binary patch literal 15142 zcmd6uTXWmGy~W@ADNs!x+Bp_C?-xJ$5a)l z6Jk>}OS$KjsOxr*y{T5eXMbx4cFC^=^ISGGo!})~iN5Dc(K~eRqN_wx_Bi$LsxZ2y zx^BZ)LKRvqmsQiV4{h01{~E*>eYQHNDshObPyWwXr3Xv-8Kw2?v~F+9d*^%4IR7QT zWfvRqnRlCe=lgWN`uk7)U^?C`goHQbz)id8_@~*5@)AfRr1?CcE-EnlKI{q^Ib1w*}fOB z_h-6tGoH7DYK3p{sT)?T8S0udUZZJLYbL*}ik7Xrwkk!lVdAC`>x~#XCi)F)7mKQ> zIIGtEuyWYR_!MxE=!$BCsuCaY! zF|2V*DAr*Ym8{EH@Z?(MQ1z@TSJ_;~z7 z&HJkg9YA*WJ#@vUKtF%icAHCf%)7R(8otMp#Pz6z^<~?r?)yI;`y*P!pI8{Ab3aZ} zIzp^?Rm&?}RV!!NRd_X<%Y&lAt6Q}Z`p@?f5YNigR;@uQrVY35VEomFU(Hz-H5W%j>g5mDsjndfDxAEeyP zi$%sm&kF*1-|DWv8SNKWRnv%Wg7@tE=>7riq~z@9q2E+^UW6dLuxF$Fa40*DX4r3d zBT5n`D-X}X`=_e7x@E^wu&CMD0)9xom$J#)2R4(;FpqDxh4ZGRCXL5BWt}~KgoORh z%W4f06;jxD!#;K$Kl4IYYtt6&)6j{%Ebz2k?STEM$h(1ew=B`P5B9x;9p1~TW<~u|Vvn6dM(e8Ig9eCh)3OhhB!3hJx~R8o2qb%))}to=n3r4&fk7KfA{*BcI|@wnJP~oHATIq)z{&k+{w4%KG=(*!0}wF z^%J-+7J1<>@)+6}dUJ?mI?vs>oQuNsJ-=A+!lPbpaIYQYUEC)E(jg!ZaUA-I>pqEl zG&}w|7hQKtm3_d?e-O6~B(9$@Kl(oAA9cLEWuJImJ^(wrX>_Zk7FviBXlfzjlciH|3?*}X(FyG6lqH}64uCyir2eSr6# z6S|%oQ0LjU_GeP#VeQY0O^fCRW3OqS?z`SYw0|Lb(Mc>TdRuo4_o`seXmm4jTOB~+ z01vH(1fxynrN$xzfF6N%(7@=(MqEZp0}2PIuiJW9!?Ozv4{o%>wiU3~g@8Eh&q`O! z5JM7qRD!XZLX%!s8ire4h^)B0Xi0Y}&ovd)n8vUH$|0qS-j)3zH#_W|8ZKaD1JI-L zQfRDlk5|+FUzR^UJ1KR$6d+A}hPQ>mf)jvNwI{!$Q*~R{gu_)Vyjn5};eI5M?t=~?6 zz}E>As`rHc(D=Jvf01QDz_VgrgdU%Vp1+uLF9rM)KPjR(OA|LYC26luUF?q6PZk~y zj-${ExEqV#!0W#g*L(u~R2AM@MiKUV)f81(m4Kw(b|(Pr!-^kocfue9rm5nrve7_pg$dQJ*ZPlF2&`F7k%9?bo^ob7p zWizHxB&SlOsMP7$k)Gp?RV^jfh^pjE(a9P;JSC>6k5N}0pV5A%RZ53%GODAo7-U-c z5*3Z@(ycIc*$H3P!emsZ7*rv*hFYCp)%>zu;gcVGq3$hrbSn*HK$Xn{7q(fqd81nm zKc?|->?b$s~YN!2=1h1rg4L`yPvw_xR6`PCrRb&umH7KK3sE$DkevL0a5bMf4U_C(<2k}5OF`sXg`)w=5 zA|Tk^>flF2%#WNffQcecHxV%}!$>AYYu0^zTf{yNqE`c!pNIOErFO8AJtSkV8?yPz z-D{?UgCla`%z-egQlKMg8I2Wa3@{3X!_Jfxjo(c8Lm|*qKOO+Gg1Sz`bO}}Cu-C>e z*dd3$Jk`cj5l74U5n}QfT~QrJ7Ly{Vt4&mE&|HTA<38o^Y8SDyG(!Y{Niw9r?`4j@ z$6gHGtpKLqBRn54%E%Ivr*EZ9S)BffMG2-8Fy7G3VP@0kM(Q3kmmB;h>b z3o#ED1)pbuAI(#qv@bJ!JJyO(r}mT>>1d$spr< zCyQTqpV9P?5789K*P;4__&?DPYMvPLU*?SyUY`T$x0r-rXT=JZgQVKl;fLh2q?WnW zneN$kgTaE`r0`26*1H3^fj*=nX%KbLu!njD3-DN7@}yu zs$q{4$hpEU)4Ag&Lq`Nra`M5NizK`u_6pP39cH_F98B}Mf5F`N=e8~P*ac?SFWC!z)ouXdFpErzzfIuOm3}##gV81l zG6Y_sPdkfR;Qp5fIaYpr`NEyHTk1wJ1@O_y;fr5?J)}LmQl8VXFx#pOf+at`ioawA zzMa2Wm^!Y}oyYxhoR^64<9HtA-eMk#GM%Skk}uurfS55z~343Tp)X`uDNVm7~_~1Mg)D1U;ag|vyjaZ7=;m7USf5@ zy@H;D;x`?ZmtapRmllQ4_j4MM%C;u%N6q zIadQrvsccxPH&mcLl9(^+Kl19oE}!e#Yk(a3o`c+^aw4+Juvi|_UhWUibfz|+|@L& zJ`*R{xPz*yvYZj(;?JvQDx-q(H8kw)j>N}0Qr#*M>W)lCb|;OZ|JZD=m@qNN$wsd31E)lAmHD#Ff>@) zmWxQrg`{8rZrzPnR$L;;SwS3|_TUT3t+=zfrsL2fX!XypC+|MKeo`#XR6(}sPqac_ z=n=KJAFr4J; zizUOR(1eQ~87Waaq2F{7C~i{CkbK? zwgMkTdli%@GRrKVFt1mw>M_?Y+l~Z_9U*r%e*H-Bp{@inl24*rVY(J!Ns^cahIiN- zBP?;j-qgL%UUZu!vh4v&ZV&p~=4vS#N11R9=?Q!<{`T(8%aeDy#mshD^&?r9ZB_=p z3LKBH_kL1Bt>|0P8|kNjJ7W>`R9pA|4!;2UrJ|O!KK3+V+{?zPtNBU_2U+6 zqS<>G01WgVn$~>|eldW%Wp6R|=^u#Ke@OIFbYL4fR-}`5&F=42AhHKcZK>UAnKRiY zSN1)^;WWcCGi0FDQ6?b9E=<%!8F_O!xAfR?P~jI-*q1X@u6IVvK2e@ zdTFJaDIJ}=wZz7dYi=5^iBeSHGEQU~=R79G>_pmj6K5#yD@fmv^H#hiD@{+@Vdr{T zzqGKs^yk zZsZD6Swm>kn9{&YkLx<|RP0D$930qDN=x$rbRm>Wv(ykKHC13+&(=f(%?>Ml;k)Do z`7nE5VXco?LrRRuyb@h5f1QDK{^B!!&eL5%Wx~wF#oH>AKxM)xn)_*Ljxd2x4|+LY zI2=Adz~@r%9)8~#*{R69I(%_*cyXdT!A_O=RTXBtijf%!%CAwGfYv8}yUK)eS)7@v zctT}(5iQEx6?5S&@;R1iig}uP<-Fu!?B&8Oy@FP47=uq$yrVLF;krqJ)uSo*OW{8~ zfr`bBwRz|dtn@sCg~2bhemk9!;T(+FCyaDCnisFl3nPR69GQ88ML+n-$t0wvv!A0c zuQ256v5*cn>E6|UNO{?w5FLBEsrhW=n*BcgQJ3Mf-A&-NTNJ7v5tYbyk|2Tw(hhJU zDqigPQJR`Avn?tUdp~CK9)GnVKl1m4q<_H5?EDw-9*twRm zX>+g=61h%A(=pTJ{p{rI{KJ!3$|qHjZ9RswniY?r_WvPF@%MrZ#^#|g<$=YOm{iIZ z_`%_vV{PO-{~*{Jz<}MCnQp)A?1R?Q%nGnAuWc>*^Y`#vNJhCAa7(Jn z%n0)E@Q@LiRsA1-xm^D3)$^xM&kxU+myaLsKYe(L~x2Nxy zFJGUZ9v(k`zdZhNb9wdj@#D*<%a{AFPxs$nzFwX`e7Jx7fYYBoU!MQ@&!-Ph_ZJNJ z!NYQp54z_2OXbletY~{<9g=h->c;hBF#Y`;dA}hLEZp- zdn)=>Xa(lu%gyCC(dqsZ*aORIN=F7mZid+7isH@X?nU-If-n_Dg;l``X$L;D62$1V z$Vo;ZQ08l1To1gQm11aL>|9=dt7k5nUE$83yGvc4XwX#F0Y?Ci)X#B zL-!ABQn;Skj#wt#JQ!lWe80K8KVmi!G-!0``(@tel=MpY{eYDs1fUCDgr@$%-8O4S zCRQbfBLajD5ZqjTMZVc)0}glj*TU~sFieIQdSZU(a5<9c0`ho8{%_0ZVPe}MmB!p$ zetQ1){p-s^Nf%EPfp_j?DtHgc_;w-JLLI)a8uHTkT?_|ul?9g4VzomtNRQp(ZTU9u znb8jmpf}VW=FfIA)9Q*?S9<)1k{@D1r7I60P?w)=6}%#19H8{Rbey`r?1&&&@HvdU z+e&X!RbsZ2_cW9FDq&5S`ANKi3?TA2Ao#_VX z6rGW81eR?3@bdA?eG2~a>hDU}uwv?ND|zyia-8#8u!E-NJt>d58CKN&((9nnBO_J} z|LP*T#TY}X0eR=@%d7&RlNO>eU6eLWc5G;ST-a1`1LJsNR}|u>5&GPdsqi4qCTkLN zYlecmz`b>Uqfko|Dl?2Cvi=WR(}*Za#uB2(FgMos4~XmY*T+vsrHf#l^{>>BB&~+7 z{;<2hLR+1rQN-j+T|ymjF@xl>{gE70x<9T?F##_bmQg%!A`{-!ZvoJO>(XK@ll7(3)0DOig+lxU?eLFNmc*q#Qw5lC(jwyu)~<+}h$2dc z;O}ZG30DjnBm@tGFh!r7U~4k!z!YO6J*}=wMkSBNsRr<^+t|ZDA0~XRn;46!5eo;& zYU#@3n@cG`jw2vwDRGs8(1@|2bV(AKS*>|lHCX8DN!12(#1-SED7a}?$OWMeq1E!z zVKutA(7bw47swP<<32DdN-IL|NyFAfX?uBVNY13DEjO2DR~9 z4otA@`h-FXcz5Yr-f@UQX~tGXg;ppv5T9zN17T&`X`{(n)lIQ1*(kZ~Sfm6P036q9 zY!*s)B}$P4B4+X%-D;qj86LuMA2ry$@~)uF{R00eUa51HsW8sG;-HVI{mCK-HERUL zbBjU=d1bXYLXU9{LYalDAeqDB!XE6F-Vf=9oRByo(ZkuDE7QiH95>b=Fu zH&7gPV@`npSooCe>SzyQC^+&N?VM7f1}!WO=@2}6$`rC0D8=k_2sv8LX1K0w$81Mb ztCVReOzMuhf%_92u0PkY>Lle{s_GsT2AWY)gBqub;#!ZI90>;Kut|_YY#dg89fUKU zV7{h9Ls9z?C`P@k9-B9Ri5VQkzs}GV*V`II%hW($WFkNi(MGqgU38ChYl=Uv=;@%< z+V5l4U5U-;1*y?5)7>&55?`KD1Pe&QSTrCTT`(GiF8Jlv2Bf>nH+^o}SGJXz5+ccR zgD4fdYVwj!sLKNFcW*l7qUrQD^2E@*wis0xf2S6u`Uqpvc3LTcd#L8Dc9JaoN3f+He{<+ORCPif|TQ55}>Kno$EPh zbFOirOai&mcyfY-1%65zH|Jg?WFHWR#p~Vta0Qe#Y7yPZJ5#9$mc_wMHHlD`7C2Gc zy@)@7I<7S2h`e z8b{sKZ{F|ZYBN>)zSE(AP}&iat#l*}5=cV3G0b*nNoTF%7%LhYSj_aDK!m|?vn2{C z`9gX^k7}cW+@R8=hnRhp@{MlBj46>Fhy|8RwAK`Gpq-$3>!wvPv7aaUx=aPb$)6rn zCLlxTeZTAO9h%{HKH` zX2rG2GJ!C6HFP;7uat8{7H}1Fc5b6T8SvzXvkY4Xkgs*nnl!_SF-a8jFfO8^&zYE5 zht>F!Cz@vRYR%O7HSeLHDefs#GDi9|buRT&sw(ClRC;?apd77sgj=5WjerGeAb?8r8kyMe~SJZ2hrw|3qH77z)B;}lu zo#`J!{wkwNMFzjsf5o5B8>9up``&mt3gPhrJ9;v&J5NBF-d!f&T>h&2%w*ssMU{r` zuOHDT{#2%x@{!<54K2gM=_*b^(JEARRVN*G?H9e8Q*_jE>>@>~B9C00iVtlju&x|m zu)K9YHBvwk2)Q&!M6lr&DV2IT)giSy3SuxzLzQSH)Q2&pvWN|u63O|N{oQrRVf3&_kuha8p4Vnyd?;QiJqCL##V6zV5jl7^NTV zj3P#{Aif@pbEdW@t7c@_zc{r*Mio%I#U`P1vvi`B-pPTt$h3E?f&f1xwMOrpB?l2A zGl&#Gd2w9>b(7IfKPo$fAb<@4GRdI8Du^X#%lNvvk{SB!%$#A+pO4zTn(fdfD8&uC zGY3_CAGsFs)UuDnsKnIXzl5SOXek_ z)TD62-3to2vj^vSBEGz>j`;$;T0geY07lJ~jB`(K!acWjA zv^2Vy80OmiUIeBxUQPM4S6FI1S56c^y9L1uv2zlC6T0!;8f2+s!K(C)foB@WOp;*L zZ^q6ULv^v|wXia4X zC4&`#X49@bt5>8?RvH_#5PVEje4xtlqQAB>PT&^QV6cslSc|d&#b%}_XQ0jGjvHDq z_=_4odm_q8mBd#pTF*uloIIyrp$UVPkyr7J%n% zt-(nJFxjy!#9CbfMdGh)tqp*8YP~buFiT_@i9O-77Gm!AND=I&a#rm4GGP#BgDzIg zDCB&bH6o1no16fD;3#-kwRo-VnI6H@FbF#r7(MW4W)`D(j_Lz8iBv`T9u4DxrP-vN zumU|1*Y>jFpBF-k+2GPy89GW76;2Q^PQ#7e&!Rg{pNDkCh|0|x1xKAmD-~hO>bX)d zA`!?FRvW+1$sk*Wv1UViU4=#yNpV#Wy`)>3Kp^W!3P5{3IqXsfgl1g~Cz+5u9sIU! zu%YPfUF33I@G?2pw7A@%EgZxmCD|fFii%UH!X!$a&8QuIQo0w=de#(`IsNELomv zvc2^bX8!edCYT@XnhDP6h+iC^*dop(N@WDxW&bgY3*`}kYnRYZX%JqADfR8pU*L5#4d1VU1Q3RW(=!X}P&2tYz;pS3W;#gfs4Oc(n+F{ojA7#(Nj?~2<-S5bG zgQhY;)awbmKe^$rQe4&-;7+tnOP~c|uiDc!<;CJ?*L}A1V1N!ki#EMa{jnZOo1j%& zmbD^7=gh(#gr#Mc?m*dv7;evW4L}wmK#@MF@*dhUId%3uV_5Z!x?Jjt!OFgAM-PY^ zVEcK-EOx7}Z#h`aLFJo;73~$R?yMm!{4sB>wTuT}Tk=*@vT8Y0Vr3c2{s-_&kSc3e zR~9A!9%0q!D$2o_Ild-Q`XI$}!jaQE`)g(T<3Tjr5Uvnv4VBRl{5REDUB>|GLk%~-eC7aYGIfQwnXn_q7ei3wy#qzjZtNQl1_dy z&!zwTY$NW=sN1VXRb0*m+(Cr1(=xV3F>RD9-1Eq>5(b+M6)A!Dg1}H@gzut z&hpAn343$-oejJDsv(~5(t}p~=uaCkX!rp>ncI{&41^WdlZsIsv;iwNS`T+4m$md- zQ+mb1Jw*8&%hFpANJXCIS?PLIQQRIg0XYd~<`ut`Pu_Qf<#1yAiX1Qv?T&wGG+%uE zVWI~!S-s85&bw+|WM%0LWy3TWNr=Ir0N{!~wACUB^I4Cds}{@P1-?lI((ksyJy(xL z^o2~dqQg8sVA&u(R+^Z|1>3W-STw}O&C3r zANI;7%=DuozEWSHGpc>mv(C9vq^oF51Q>DOg>0f73Bt5*MNS%+DU}Aue`hYAQj0cq zbq1J;Z}z78d3V%C0iY2OAr(ge-NCD)1qTg1v1Qrlg&@GWIojQy1w!X+6u z8U-$4LjCcBYPQBJDQasnIcnUC!#+^LgY2zGhF+^uURiCDv*$>~Qyei^2i_1TVkleW zl9zMmgBNGmsE61@^gMB5#bn{|OZ07@4S6jE&p?g0t06^NjWQU6ZZ@s{A-8! zGwNA&M!OxLB4DK03i8^2o3)I$hz4(kyt6NOxhOE8$`WKk=|nZ@5+5zE%aqAz8mo9| zmE|q$(FwGCOoP?N!4n(ORofxecFgDv;Me8=ScZ^B&?sU{zluMHY zbIZ448s*GyP>##tx(0f(GpdH}k8y*P|*IwiaR_Ivs{|bjhh-ODt8`Y*ZioWDZ$AA<8WSOY- z%K9*BwnC2mpk;)~3@=^KK%2Z*aN4R_1+NUf%l1=CgY6^pLpQ)u1DS-$T#d^UGadP# zRSA4zgJO47wyO`zu-Plq7k(TyAep8-2!)s7@3>cNs3(-NX-YHG(8|($Adxj@XF#4> zL9Avpo#RUNlkW>bKF(sOv*LA=`c;SAeE}b*i?URC4r;aQ$($ONv|XLG)J0XBf?R9b zF}2ETp}#6@`zsLV++;xI%VzoH4&v-|a6;=^0CDoTPjJW3uY5M0cD8-kjmg zlYPIW?3tdWb@d;ZL+g6Uf6iS3kkEjJq^@-9H$B=~CwKud$y{OYgi^hNWp(P69EN!n zFWAAVI1aENY1x$go>)yj3B%I!o-?N-A|iw$z}PKbxC1W3S^`sj9A{LB6wyWFnVi>w zh3-pnV<13x(&Y5#we3Sp&Aj;gcsx8Bu}HSXNzQ><28xQc-!#X+Ks5HFm9s%oR3B@6G==bQfXPS7-f)pU~Qfm3b<=6>l)-5YWHSG^*CY@`57Sm?!WZ(RC=+jp7nfkUK z3$u^?Y(MRVYT%zDf0TmVe7&tD&PzF!16*qHcLHC|Dozj7MgBE{7 zWAd6;gGcoR8#v8_Ree#WRHo8=r5V9Ks<3w2?L(#D+@CIw6IleKp@kUHHjc}``m}Nw z5K5(J`#74kz~v@lB4~!O=7gi*)%88Y!*}dNx5^}ZSvc)Dk2Fc{VI74g)*u-Y(?cxJM|^o$;k&0pHM5y3ly}ENUU|3|kkVs?sKUnq)z71XyktvZARK4rJH{dfwNgZKk9ZvdE;PKHNc3=aWFCzkJCuz`w>4s# zX}PiwjB#bciiY0Tk3yxm1vk*@j&hIVE~xlSQIQ`7MhdZT|4pTxNjGeX3JsXDsaaGN z1h=Dl)B4Vf1m$!Sr|F0D+1kk5-@U-HOseTAk5+t(bd&|l1pWLuf~_~3Y~V@f7rl2C zNK+hx($<3zl=Z?g`)QF2pi~mTq|NoL4+x@!tEY8R0*SK_Wf~5-H)j5hfpbxA5*Y+# zQ4cK#Df;Kwz-6e!F1cs`+qT~!6yDxE+kXSH!o6=9B0^yLy0A^55lMksKT*^`bD`|axWN~eWm@mB;1@7i2jXIU9845OPKHn%gXk{XUz z$ZN0Qt)INKoWV;4Mw#STAqH^BA)+Le+TpRhsp_w_I~D;@`q<1y7K0q9S$2Vy(+R__ zjc*qVEd+Xy@llonCBZ71L~XH4Al;FWSQ&Ve{LTJkEtAn4P1;}#ro-lsSVs+JWTl^* zgqi|AZgZ@=uU0P@?s7+iX_@JnoxcKFgrVX@BSe9kew#C7aT7$vqpT6OP-A5Bc*eAw zqdlf+N6%Jh@2=AwbVw42HYOLgDMNJPLI>#strdS<%mGs!!IedL24VFiwxnP{0-jGn z7%U7RWK1$iR(cbqdO^vd(1S5(?e=N_K?yEJ>NlfNsZsw8bU5yQD*n--klofsOITA^ zycrY(ow{O@=$X0Svd(0uR;6B2Q13|6RlkSpf3i3f@l zsvOWIz4!IS0<)qub?p^|0YM7%t$~(7uS1)mty#qxBMZSYzY`x(RG+H$K0@Z)`XD`G zoN_q7N8BWYC*ye*AVIkB58l17X>d=y&DH;A3Idy{}nV`U27@UPK@l-^MW!pdr-Du;dPH zhsrHnp+=t4MOey39t(-(mpM>=P{mMbhF^tD`HkOmm5M^;hw?m>%basLiN%vpQdZ~N zfomYfQSB=li{d~!quH5Rr2fhKr#x{75CpPkBNOy*pOltkZ5oUraFrxEm zkf*NwIA-pECrK5+_DuO43si|fn#|Q0AGlnT!b`2$%N(mZ>^tl5k>p;J{|dBvdKFv8 z&MJWuzUfYNJ$fh>S_vf=Vr@0bORmO5le($}y+&6l4A^@j7SstR8lIydi=G-h9!GvQNi+Mh-CO8PvM z7zH6VR0AJXYpqH!-UE19n%uQfwWAp)iq>O9i0MUiFOIItwi{>fBOtxvc)T`isFWgk zSK%w}oI3+9MwJ8MEc1Z^!O{4a;~6~3;dOU%rQhpHep_F7b2PR0Ra+HdR0*F_fh!Wz zW~-7HtC_5`eKbmFNoO5fJEHe6F+OZ?wf!^Q*xZF%56q*%OtdSR0v7qF0u~d?F;xam-l-4)*n&_>AZjXqJkMQE*6KcgtZ zP1l^QlJ;%P;||%rrT15TibhYZ>tOUK%Ewf;6!kZwOP~^Spxau>a zwE{IP>^;xoW-f13jSH0;+l|Ys)236vCR`F(J~e!a7y#5oa@$vu3#R`c$tCO zW{X+!*l>hLOq(;l-HIuG;zKlnwf|U|I_K&}_3!T1VNubqRvawkDc(V@jK=9i;&>!02fbPVi-}2o6J;o5K z3s9{I<`Ix4OwrV_@4W1lo8Y$0*;GF3_KpuoB`S&L=l~qbo30E9nv%L`^Bx0ZQ?4B4 z6gmPO&>RVl7(fOU*{_3OA)Q78fp3%4pxZNzuQus!uQ^m@YmLBM?jU+}l#ooht$Wj~F7Tij(7 z;uMiuvZhK4Ohb|_SIuBIHqaWj_B|uZHtKlQL*u8XIL=$FeUCWdC`qZ6c}cwY29iN? zK2R2hbrN^l>N%)aSxGw~DMs$IzynkP;5M?!zQnFAzQ3(b7o&!IbzM3uF32m4(jzI6`h>+i-~5xcM9l}b5__S zCV0`;!y&8npDaQ-s%e@AhNbNH-s98qC%V$Ktrm;@vl30^=sB96(*>MdsEN8D&qj*;oXm-5kSs0e+=|gwMmU!)uG{W$p3!$b8izDH5uT(*)4fNd}k|kEviAn^tcSH%DPb*r( z{U$5iIGWcIf5oj$@s;+b+_c>Ue|_!oN$;tNr+g69#)N({*Es9K|99Wf!9C+PrHe|S zkFufb?IFvB?bBW?7Wmk*t32nVsqU1G6$g{DkP=B~XJ$)DDif=*cBZs-%BiMGRB`y| z%;v?!qfoU^3xYRlT6AypDB2~>s?*YpOi^9;t1h^W+a!#mcvSFBDaBp|#QM>G0KCdz zmYEs4XR}ia#SyqQA7V4fs7g|WFKQ<2W_XIk!ekrEW#yVLx(WhlnDJY$K@(!$k*HPb zs$rvaAz1m$-m)!HdR4%d_~a-EbHzS)F%mJ%FKA0B_V;c4z2a$!L4QVq)=Dn>RT&?n z%>uXsLmiL`Nv*izsvg2AN+AJXCMRV^i5Po;%7qS7iEMOqhK z?#d2JCVJnq07ScVDgjAQf1TR8%3|`+6-9}&%QgkR!+_dPVx5I z)wwNC!)WbFNLLJ}_R%nC&;8nQVId%Q?Txr?8uJRT`iPNZSk+;zP@E6!yeD=Y_(K5K z8U>y%J6~sWwkp;_4H&W*h2Z`FOQ-2g@`V|*e~m!QpySN^LGp(k{0)m#0s=y_y6c6D za6oiww=(pouc9=s6D9i4I+}NpO=rtMf0J@CctQ2XUoN$xQ62Q5VhNpNLuvua!hGG8 zYaW$UnL~s>FWN>NC$5L3%ck3E3~Z3{Sb4$qStnj}7yauo(Ap|UdSy@B4*1s=%R?!d zT;8~01L(|Qt$;F>9iq_nLT$oynnY)iE;Vw3pzQ@%AGM*xcT2z=k>C8e@Ojm1(%P?d zvJHF7yq%ZPVt>CMYNPq@D;=vD!1Z934GQ&JuYT&W4@XD#sjg9elo%x4%9`>lmEu6X a>RVy5&K2MF)3cB)rDfK6F6935pZ^DNFpARv literal 0 HcmV?d00001 diff --git a/bin/types/readme.txt b/bin/types/readme.txt new file mode 100644 index 0000000..da1dae6 --- /dev/null +++ b/bin/types/readme.txt @@ -0,0 +1 @@ +Test data obtained from https://github.com/xpol/lua-rapidjson/tree/master/performance diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index f37f9e1..cc676d8 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -120,6 +120,28 @@ struct UTF8 { } } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + template static bool Decode(InputStream& is, unsigned* codepoint) { #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) @@ -261,6 +283,22 @@ struct UTF16 { } } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, (v & 0x3FF) | 0xDC00); + } + } + template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); @@ -386,6 +424,13 @@ struct UTF32 { os.Put(codepoint); } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); @@ -501,6 +546,12 @@ struct ASCII { os.Put(static_cast(codepoint & 0xFF)); } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + template static bool Decode(InputStream& is, unsigned* codepoint) { uint8_t c = static_cast(is.Take()); @@ -571,6 +622,13 @@ struct AutoUTF { (*f[os.GetType()])(os, codepoint); } + template + RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + template RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); @@ -604,6 +662,15 @@ struct Transcoder { return true; } + template + RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + //! Validate one Unicode codepoint from an encoded stream. template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { @@ -611,6 +678,10 @@ struct Transcoder { } }; +// Forward declaration. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c); + //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { @@ -620,6 +691,12 @@ struct Transcoder { return true; } + template + RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 5e5cda1..7c8294b 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -108,11 +108,21 @@ public: // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count >= stackEnd_)) Expand(count); + } + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count < stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 0023abe..a90a4a0 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -614,11 +614,25 @@ struct StreamTraits { enum { copyOptimization = 0 }; }; +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream& stream, size_t count) { + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { + stream.Put(c); +} + //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { + PutReserve(stream, n); for (size_t i = 0; i < n; i++) - stream.Put(c); + PutUnsafe(stream, c); } /////////////////////////////////////////////////////////////////////////////// diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h index e9be849..40b51cd 100644 --- a/include/rapidjson/stringbuffer.h +++ b/include/rapidjson/stringbuffer.h @@ -48,6 +48,7 @@ public: #endif void Put(Ch c) { *stack_.template Push() = c; } + void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } void Flush() {} void Clear() { stack_.Clear(); } @@ -57,6 +58,8 @@ public: stack_.ShrinkToFit(); stack_.template Pop(1); } + + void Reserve(size_t count) { stack_.template Reserve(count); } Ch* Push(size_t count) { return stack_.template Push(count); } void Pop(size_t count) { stack_.template Pop(count); } @@ -82,6 +85,16 @@ private: //! String buffer with UTF8 encoding typedef GenericStringBuffer > StringBuffer; +template +inline void PutReserve(GenericStringBuffer& stream, size_t count) { + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { + stream.PutUnsafe(c); +} + //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index a450456..13db449 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -189,15 +189,18 @@ protected: static const size_t kDefaultLevelDepth = 32; bool WriteNull() { - os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; } bool WriteBool(bool b) { if (b) { - os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); } else { - os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); } return true; } @@ -205,40 +208,45 @@ protected: bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - os_->Put(static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteDouble(double d) { char buffer[25]; char* end = internal::dtoa(d, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - os_->Put(static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -256,7 +264,12 @@ protected: #undef Z16 }; - os_->Put('\"'); + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + + PutUnsafe(*os_, '\"'); GenericStringStream is(str); while (is.Tell() < length) { const Ch c = is.Peek(); @@ -265,13 +278,13 @@ protected: unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; - os_->Put('\\'); - os_->Put('u'); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - os_->Put(hexDigits[(codepoint >> 12) & 15]); - os_->Put(hexDigits[(codepoint >> 8) & 15]); - os_->Put(hexDigits[(codepoint >> 4) & 15]); - os_->Put(hexDigits[(codepoint ) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); @@ -279,34 +292,34 @@ protected: unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; - os_->Put(hexDigits[(lead >> 12) & 15]); - os_->Put(hexDigits[(lead >> 8) & 15]); - os_->Put(hexDigits[(lead >> 4) & 15]); - os_->Put(hexDigits[(lead ) & 15]); - os_->Put('\\'); - os_->Put('u'); - os_->Put(hexDigits[(trail >> 12) & 15]); - os_->Put(hexDigits[(trail >> 8) & 15]); - os_->Put(hexDigits[(trail >> 4) & 15]); - os_->Put(hexDigits[(trail ) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && escape[static_cast(c)]) { is.Take(); - os_->Put('\\'); - os_->Put(static_cast(escape[static_cast(c)])); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { - os_->Put('0'); - os_->Put('0'); - os_->Put(hexDigits[static_cast(c) >> 4]); - os_->Put(hexDigits[static_cast(c) & 0xF]); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } else - if (!Transcoder::Transcode(is, *os_)) + if (!Transcoder::TranscodeUnsafe(is, *os_)) return false; } - os_->Put('\"'); + PutUnsafe(*os_, '\"'); return true; } diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index 2b0984c..2afe641 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -65,44 +65,87 @@ public: PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {} virtual void SetUp() { + { + const char *paths[] = { + "data/sample.json", + "bin/data/sample.json", + "../bin/data/sample.json", + "../../bin/data/sample.json", + "../../../bin/data/sample.json" + }; - const char *paths[] = { - "data/sample.json", - "bin/data/sample.json", - "../bin/data/sample.json", - "../../bin/data/sample.json", - "../../../bin/data/sample.json" - }; - FILE *fp = 0; - for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { - fp = fopen(filename_ = paths[i], "rb"); - if (fp) - break; + FILE *fp = 0; + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + fp = fopen(filename_ = paths[i], "rb"); + if (fp) + break; + } + ASSERT_TRUE(fp != 0); + + fseek(fp, 0, SEEK_END); + length_ = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + json_ = (char*)malloc(length_ + 1); + ASSERT_EQ(length_, fread(json_, 1, length_, fp)); + json_[length_] = '\0'; + fclose(fp); } - ASSERT_TRUE(fp != 0); - - fseek(fp, 0, SEEK_END); - length_ = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - json_ = (char*)malloc(length_ + 1); - ASSERT_EQ(length_, fread(json_, 1, length_, fp)); - json_[length_] = '\0'; - fclose(fp); // whitespace test - whitespace_length_ = 1024 * 1024; - whitespace_ = (char *)malloc(whitespace_length_ + 4); - char *p = whitespace_; - for (size_t i = 0; i < whitespace_length_; i += 4) { - *p++ = ' '; - *p++ = '\n'; - *p++ = '\r'; - *p++ = '\t'; + { + whitespace_length_ = 1024 * 1024; + whitespace_ = (char *)malloc(whitespace_length_ + 4); + char *p = whitespace_; + for (size_t i = 0; i < whitespace_length_; i += 4) { + *p++ = ' '; + *p++ = '\n'; + *p++ = '\r'; + *p++ = '\t'; + } + *p++ = '['; + *p++ = '0'; + *p++ = ']'; + *p++ = '\0'; + } + + // types test + { + const char *typespaths[] = { + "data/types", + "bin/types", + "../bin/types", + "../../bin/types/", + "../../../bin/types" + }; + + const char* typesfilenames[] = { + "booleans.json", + "floats.json", + "guids.json", + "integers.json", + "mixed.json", + "nulls.json", + "paragraphs.json" + }; + + for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) { + types_[j] = 0; + for (size_t i = 0; i < sizeof(typespaths) / sizeof(typespaths[0]); i++) { + char filename[256]; + sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]); + if (FILE* fp = fopen(filename, "rb")) { + fseek(fp, 0, SEEK_END); + size_t length = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + types_[j] = (char*)malloc(length + 1); + ASSERT_EQ(length, fread(types_[j], 1, length, fp)); + types_[j][length] = '\0'; + fclose(fp); + break; + } + } + } } - *p++ = '['; - *p++ = '0'; - *p++ = ']'; - *p++ = '\0'; } virtual void TearDown() { @@ -110,6 +153,10 @@ public: free(whitespace_); json_ = 0; whitespace_ = 0; + for (size_t i = 0; i < 7; i++) { + free(types_[i]); + types_[i] = 0; + } } private: @@ -122,6 +169,7 @@ protected: size_t length_; char *whitespace_; size_t whitespace_length_; + char *types_[7]; static const size_t kTrialCount = 1000; }; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 0594171..b9ac395 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -45,7 +45,10 @@ public: temp_ = (char *)malloc(length_ + 1); // Parse as a document - EXPECT_FALSE(doc_.Parse(json_).IsNull()); + EXPECT_FALSE(doc_.Parse(json_).HasParseError()); + + for (size_t i = 0; i < 7; i++) + EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError()); } virtual void TearDown() { @@ -60,6 +63,7 @@ private: protected: char *temp_; Document doc_; + Document typesDoc_[7]; }; TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) { @@ -250,8 +254,10 @@ TEST_F(RapidJson, DocumentAccept) { } struct NullStream { + typedef char Ch; + NullStream() /*: length_(0)*/ {} - void Put(char) { /*++length_;*/ } + void Put(Ch) { /*++length_;*/ } void Flush() {} //size_t length_; }; @@ -278,6 +284,25 @@ TEST_F(RapidJson, Writer_StringBuffer) { } } +#define TEST_TYPED(index, Name)\ +TEST_F(RapidJson, Writer_StringBuffer_##Name) {\ + for (size_t i = 0; i < kTrialCount * 10; i++) {\ + StringBuffer s(0, 1024 * 1024);\ + Writer writer(s);\ + typesDoc_[index].Accept(writer);\ + const char* str = s.GetString();\ + (void)str;\ + }\ +}\ + +TEST_TYPED(0, Booleans) +TEST_TYPED(1, Floats) +TEST_TYPED(2, Guids) +TEST_TYPED(3, Integers) +TEST_TYPED(4, Mixed) +TEST_TYPED(5, Nulls) +TEST_TYPED(6, Paragraphs) + TEST_F(RapidJson, PrettyWriter_StringBuffer) { for (size_t i = 0; i < kTrialCount; i++) { StringBuffer s(0, 2048 * 1024); From bcc3fb6d9e853c75d8ff8647b9e18abe66a1813b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 31 Dec 2015 16:07:07 +0800 Subject: [PATCH 63/98] Fix stack reserve bug --- include/rapidjson/internal/stack.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 7c8294b..3d691d3 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -110,7 +110,7 @@ public: template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count >= stackEnd_)) + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) Expand(count); } @@ -122,7 +122,7 @@ public: template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { - RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count < stackEnd_); + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; From 122c7229936fa8811b78eea78c311b51c53fc836 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 31 Dec 2015 16:17:52 +0800 Subject: [PATCH 64/98] More LIKELY/UNLIKELY in Writer --- include/rapidjson/writer.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 13db449..63b88f5 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -146,7 +146,7 @@ public: RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); level_stack_.template Pop(1); bool ret = WriteEndObject(); - if (level_stack_.Empty()) // end of json text + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text os_->Flush(); return ret; } @@ -163,7 +163,7 @@ public: RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); bool ret = WriteEndArray(); - if (level_stack_.Empty()) // end of json text + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text os_->Flush(); return ret; } @@ -271,12 +271,12 @@ protected: PutUnsafe(*os_, '\"'); GenericStringStream is(str); - while (is.Tell() < length) { + while (RAPIDJSON_LIKELY(is.Tell() < length)) { const Ch c = is.Peek(); if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); @@ -304,7 +304,7 @@ protected: PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } - else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && escape[static_cast(c)]) { + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, static_cast(escape[static_cast(c)])); @@ -316,7 +316,7 @@ protected: } } else - if (!Transcoder::TranscodeUnsafe(is, *os_)) + if (RAPIDJSON_UNLIKELY(!(Transcoder::TranscodeUnsafe(is, *os_)))) return false; } PutUnsafe(*os_, '\"'); @@ -330,7 +330,7 @@ protected: void Prefix(Type type) { (void)type; - if (level_stack_.GetSize() != 0) { // this value is not at root + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) From 84c56130d2cdc4ea378e5d9e33d68cf983467fcc Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 11:56:39 +0200 Subject: [PATCH 65/98] Adjust CMakeLists.txt files to use ccache when it's available. --- CMakeLists.txt | 6 ++++++ test/perftest/CMakeLists.txt | 6 ++++++ test/unittest/CMakeLists.txt | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51ee620..89a7634 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,12 @@ if(RAPIDJSON_HAS_STDSTRING) add_definitions(-DRAPIDJSON_HAS_STDSTRING) endif() +find_program(CCACHE_FOUND ccache) +if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) +endif(CCACHE_FOUND) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/test/perftest/CMakeLists.txt b/test/perftest/CMakeLists.txt index 4121bf9..f698382 100644 --- a/test/perftest/CMakeLists.txt +++ b/test/perftest/CMakeLists.txt @@ -9,6 +9,12 @@ target_link_libraries(perftest ${TEST_LIBRARIES}) add_dependencies(tests perftest) +find_program(CCACHE_FOUND ccache) +if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) +endif(CCACHE_FOUND) + IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) add_test(NAME perftest COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/perftest diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index fd2eb4d..ee5ff0c 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -18,6 +18,12 @@ set(UNITTEST_SOURCES valuetest.cpp writertest.cpp) +find_program(CCACHE_FOUND ccache) +if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) +endif(CCACHE_FOUND) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") From 96fbaef1ec17a338ec8673fab7a4d461fed8a134 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:04:47 +0200 Subject: [PATCH 66/98] Workaround clang and ccache bugs described in http://petereisentraut.blogspot.co.il/2011/05/ccache-and-clang.html --- CMakeLists.txt | 2 +- test/perftest/CMakeLists.txt | 2 ++ test/unittest/CMakeLists.txt | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89a7634..ca47d81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers -Qunused-arguments -fcolor-diagnostics") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/test/perftest/CMakeLists.txt b/test/perftest/CMakeLists.txt index f698382..4329231 100644 --- a/test/perftest/CMakeLists.txt +++ b/test/perftest/CMakeLists.txt @@ -13,6 +13,8 @@ find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics") endif(CCACHE_FOUND) IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index ee5ff0c..8654753 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -22,6 +22,8 @@ find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics") endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") From 163c4b75832a25831f974a7d0a7958f08e7a08a7 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:07:28 +0200 Subject: [PATCH 67/98] Fixed cmake syntax errors. --- CMakeLists.txt | 5 ++++- test/perftest/CMakeLists.txt | 1 + test/unittest/CMakeLists.txt | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca47d81..3c6f4e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,12 +29,15 @@ find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics") + endif() endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers -Qunused-arguments -fcolor-diagnostics") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/test/perftest/CMakeLists.txt b/test/perftest/CMakeLists.txt index 4329231..ba8dc31 100644 --- a/test/perftest/CMakeLists.txt +++ b/test/perftest/CMakeLists.txt @@ -15,6 +15,7 @@ if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics") + endif() endif(CCACHE_FOUND) IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 8654753..c24ef84 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -24,6 +24,7 @@ if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics") + endif() endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") From df76c0d6d74dafe123789185ab6e38b7bab3a6ee Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 31 Dec 2015 18:10:17 +0800 Subject: [PATCH 68/98] Apply LIKELY/UNLIKELY in Reader --- include/rapidjson/reader.h | 123 +++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 8628b53..b1474db 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -55,7 +55,7 @@ RAPIDJSON_DIAG_OFF(effc++) #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (HasParseError()) { return value; } \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ @@ -408,7 +408,7 @@ public: SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (is.Peek() == '\0') { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } @@ -420,7 +420,7 @@ public: SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (is.Peek() != '\0') { + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } @@ -476,29 +476,30 @@ private: SkipWhitespace(is); if (parseFlags & kParseCommentsFlag) { - while (is.Peek() == '/') { + while (RAPIDJSON_UNLIKELY(is.Peek() == '/')) { is.Take(); if (is.Peek() == '*') { is.Take(); while (true) { - if (is.Peek() == '\0') + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); if (is.Take() == '*') { - if (is.Peek() == '\0') + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); if (is.Take() == '/') break; } } - } else if (is.Peek() == '/') { + } + else if (RAPIDJSON_LIKELY(is.Peek() == '/')) { is.Take(); while (is.Peek() != '\0' && is.Take() != '\n') { } - } else { - RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); } + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); SkipWhitespace(is); } @@ -511,7 +512,7 @@ private: RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' - if (!handler.StartObject()) + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); @@ -519,13 +520,13 @@ private: if (is.Peek() == '}') { is.Take(); - if (!handler.EndObject(0)) // empty object + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { - if (is.Peek() != '"') + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); @@ -534,7 +535,7 @@ private: SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (is.Take() != ':') + if (RAPIDJSON_UNLIKELY(is.Take() != ':')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments(is); @@ -554,7 +555,7 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case '}': - if (!handler.EndObject(memberCount)) + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: @@ -570,7 +571,7 @@ private: RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' - if (!handler.StartArray()) + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); @@ -578,7 +579,7 @@ private: if (is.Peek() == ']') { is.Take(); - if (!handler.EndArray(0)) // empty array + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } @@ -597,7 +598,7 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case ']': - if (!handler.EndArray(elementCount)) + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: @@ -612,8 +613,8 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); - if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { - if (!handler.Null()) + if (RAPIDJSON_LIKELY(is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else @@ -625,8 +626,8 @@ private: RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); - if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { - if (!handler.Bool(true)) + if (RAPIDJSON_LIKELY(is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else @@ -638,8 +639,8 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); - if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { - if (!handler.Bool(false)) + if (RAPIDJSON_LIKELY(is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else @@ -715,7 +716,7 @@ private: const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } - if (!success) + if (RAPIDJSON_UNLIKELY(!success)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } @@ -740,21 +741,21 @@ private: for (;;) { Ch c = is.Peek(); - if (c == '\\') { // Escape + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape is.Take(); Ch e = is.Take(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[static_cast(e)]) + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) os.Put(static_cast(escape[static_cast(e)])); - else if (e == 'u') { // Unicode + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode unsigned codepoint = ParseHex4(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { // Handle UTF-16 surrogate pair - if (is.Take() != '\\' || is.Take() != 'u') + if (RAPIDJSON_UNLIKELY(is.Take() != '\\' || is.Take() != 'u')) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); unsigned codepoint2 = ParseHex4(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } @@ -763,19 +764,19 @@ private: else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); } - else if (c == '"') { // Closing double quote + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } - else if (c == '\0') + else if (RAPIDJSON_UNLIKELY(c == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); - else if (static_cast(c) < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); else { - if (parseFlags & kParseValidateEncodingFlag ? + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)) + !Transcoder::Transcode(is, os)))) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } } @@ -843,17 +844,17 @@ private: uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; - if (s.Peek() == '0') { + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { i = 0; s.TakePush(); } - else if (s.Peek() >= '1' && s.Peek() <= '9') { + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast(s.TakePush() - '0'); if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 214748364) { // 2^31 = 2147483648 - if (i != 214748364 || s.Peek() > '8') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { i64 = i; use64bit = true; break; @@ -863,9 +864,9 @@ private: significandDigit++; } else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 429496729) { // 2^32 - 1 = 4294967295 - if (i != 429496729 || s.Peek() > '5') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { i64 = i; use64bit = true; break; @@ -883,9 +884,9 @@ private: double d = 0.0; if (use64bit) { if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 - if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { d = i64; useDouble = true; break; @@ -894,9 +895,9 @@ private: significandDigit++; } else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 - if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { d = i64; useDouble = true; break; @@ -908,8 +909,8 @@ private: // Force double for big integer if (useDouble) { - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); d = d * 10 + (s.TakePush() - '0'); } @@ -922,7 +923,7 @@ private: s.Take(); decimalPosition = s.Length(); - if (!(s.Peek() >= '0' && s.Peek() <= '9')) + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { @@ -931,7 +932,7 @@ private: if (!use64bit) i64 = i; - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { @@ -950,11 +951,11 @@ private: useDouble = true; } - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; - if (d > 0.0) + if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else @@ -981,22 +982,22 @@ private: expMinus = true; } - if (s.Peek() >= '0' && s.Peek() <= '9') { + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent - while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); - if (exp > maxExp) + if (RAPIDJSON_UNLIKELY(exp > maxExp)) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); } } @@ -1036,7 +1037,7 @@ private: cont = handler.Uint(i); } } - if (!cont) + if (RAPIDJSON_UNLIKELY(!cont)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } From 45ea872f2e23605cbcf01c49bce3dc7e3a527980 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:10:34 +0200 Subject: [PATCH 69/98] Set CCACHE_CPP2 environment variable to yes as described in http://petereisentraut.blogspot.co.il/2011/09/ccache-and-clang-part-2.html --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 981ea37..a0c3b07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,9 +42,9 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 - - env: CONF=debug ARCH=x86_64 + - env: CONF=debug ARCH=x86_64 CCACHE_CPP2=yes compiler: clang - - env: CONF=release ARCH=x86 + - env: CONF=release ARCH=x86 CCACHE_CPP2=yes compiler: clang addons: apt: @@ -52,7 +52,7 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 - - env: CONF=release ARCH=x86_64 + - env: CONF=release ARCH=x86_64 CCACHE_CPP2=yes compiler: clang # coverage report - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' From 0cc5974b111f2f16993d66b316df14533ea13b4c Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:19:09 +0200 Subject: [PATCH 70/98] Missed one CCACHE_CPP2=yes --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0c3b07..d516feb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ matrix: - libc6-dbg:i386 - env: CONF=release ARCH=x86_64 compiler: gcc - - env: CONF=debug ARCH=x86 + - env: CONF=debug ARCH=x86 CCACHE_CPP2=yes compiler: clang addons: apt: From 52e287a8c9fe9af888cb0f1f9acc7a40ef1e8ccd Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:32:17 +0200 Subject: [PATCH 71/98] Fail the build early if cmake cannot generate the Makefiles. --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index d516feb..5681a22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,17 +84,17 @@ before_script: - ccache -s - sed -i "s/-march=native//" CMakeLists.txt - mkdir build - - > - eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; - (cd build && cmake - -DRAPIDJSON_HAS_STDSTRING=ON - -DCMAKE_VERBOSE_MAKEFILE=ON - -DCMAKE_BUILD_TYPE=$CONF - -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS" - -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS - ..) script: + - > + eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; + (cd build && cmake + -DRAPIDJSON_HAS_STDSTRING=ON + -DCMAKE_VERBOSE_MAKEFILE=ON + -DCMAKE_BUILD_TYPE=$CONF + -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS" + -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS + ..) - cd build - make tests - make examples From 5fb5002e9a154b57490964877aff132eabc44548 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 12:35:25 +0200 Subject: [PATCH 72/98] Run everything in 2 parallel threads. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5681a22..4565ebb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -96,7 +96,7 @@ script: -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS ..) - cd build - - make tests - - make examples - - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"` + - make tests -j 2 + - make examples -j 2 + - ctest -j 2 -V `[ "$CONF" = "release" ] || echo "-E perftest"` - make travis_doc From 89631a6190858698061cbec7cdb93b596a3b6a46 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 13:05:57 +0200 Subject: [PATCH 73/98] Make documentation only in one of the build jobs. --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4565ebb..9c6089f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ addons: packages: &default_packages - cmake - valgrind - - doxygen env: global: @@ -74,6 +73,10 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 + - doxygen + script: # Generate and push documentation + - *default_script + - make travis_doc after_success: - pip install --user cpp-coveralls - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h @@ -85,7 +88,7 @@ before_script: - sed -i "s/-march=native//" CMakeLists.txt - mkdir build -script: +script: &default_script - > eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; (cd build && cmake @@ -99,4 +102,4 @@ script: - make tests -j 2 - make examples -j 2 - ctest -j 2 -V `[ "$CONF" = "release" ] || echo "-E perftest"` - - make travis_doc + From 8e40b2062ed76ede53a6f26c8e31ac7736f3ef1e Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 13:29:39 +0200 Subject: [PATCH 74/98] Split the documentation task from the rest since references to script doesn't work. --- .travis.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c6089f..b84f7bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,13 +73,17 @@ matrix: - *default_packages - g++-multilib - libc6-dbg:i386 - - doxygen - script: # Generate and push documentation - - *default_script - - make travis_doc after_success: - pip install --user cpp-coveralls - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h + - script: + - cd build + - cmake -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON + - make travis_doc + addons: + apt: + packages: + - doxygen before_script: # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), @@ -88,7 +92,7 @@ before_script: - sed -i "s/-march=native//" CMakeLists.txt - mkdir build -script: &default_script +script: - > eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; (cd build && cmake @@ -102,4 +106,3 @@ script: &default_script - make tests -j 2 - make examples -j 2 - ctest -j 2 -V `[ "$CONF" = "release" ] || echo "-E perftest"` - From 5337e73f34017f6d2d626f1ea3c95dbdca36d027 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 13:41:51 +0200 Subject: [PATCH 75/98] Fix path. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b84f7bd..acc3a04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,7 +78,7 @@ matrix: - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - script: - cd build - - cmake -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON + - cmake .. -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON - make travis_doc addons: apt: From 918fafc611401d7cf0198fc1ce6f4f5333bef2d8 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 13:56:35 +0200 Subject: [PATCH 76/98] Disable cache for doxygen. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index acc3a04..449fdc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,6 +80,7 @@ matrix: - cd build - cmake .. -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON - make travis_doc + cache: false addons: apt: packages: From 83a2e13efb25503c7e05efeb3c7f3d53634838f3 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 14:21:23 +0200 Subject: [PATCH 77/98] Add pip caching only when reporting coverage. --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 449fdc3..865b9d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: cpp sudo: false cache: - ccache - - pip addons: apt: @@ -56,6 +55,9 @@ matrix: # coverage report - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' compiler: gcc + cache: + - ccache + - pip addons: apt: packages: @@ -67,6 +69,9 @@ matrix: - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' compiler: gcc + cache: + - ccache + - pip addons: apt: packages: From 53557c898899f813759bf217da759eea4d077521 Mon Sep 17 00:00:00 2001 From: Omer Katz Date: Thu, 31 Dec 2015 16:17:14 +0200 Subject: [PATCH 78/98] Moved comment to the right place and added a TODO. Added another comment about the documentation task. --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 865b9d5..57b1b1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,7 +81,7 @@ matrix: after_success: - pip install --user cpp-coveralls - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h - - script: + - script: # Documentation task - cd build - cmake .. -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON - make travis_doc @@ -92,9 +92,10 @@ matrix: - doxygen before_script: - # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), - # exposed by merging PR#163 (using -march=native) - ccache -s + # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469), + # exposed by merging PR#163 (using -march=native) + # TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded. - sed -i "s/-march=native//" CMakeLists.txt - mkdir build From bd1be768f18342b032e4d3e0e205fd6c51d4bd7d Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Jan 2016 09:59:38 +0800 Subject: [PATCH 79/98] Fix #508 tutorial documentation about move semantics. --- doc/tutorial.md | 4 ++-- doc/tutorial.zh-cn.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 1211023..379e6e3 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -280,7 +280,7 @@ A very special decision during design of RapidJSON is that, assignment of value ~~~~~~~~~~cpp Value a(123); Value b(456); -b = a; // a becomes a Null value, b becomes number 123. +a = b; // a becomes number 456, b becomes a Null value. ~~~~~~~~~~ ![Assignment with move semantics.](diagram/move1.png) @@ -305,7 +305,7 @@ Value o(kObjectType); ![Copy semantics makes a lots of copy operations.](diagram/move2.png) -The object `o` needs to allocate a buffer of same size as contacts, makes a deep clone of it, and then finally contacts is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying. +The object `o` needs to allocate a buffer of same size as `contacts`, makes a deep clone of it, and then finally `contacts` is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying. There are solutions to prevent actual copying these data, such as reference counting and garbage collection(GC). diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md index 37808b0..156dab6 100644 --- a/doc/tutorial.zh-cn.md +++ b/doc/tutorial.zh-cn.md @@ -280,7 +280,7 @@ Value a(kArrayType); ~~~~~~~~~~cpp Value a(123); Value b(456); -b = a; // a变成Null,b变成数字123。 +a = b; // a变成数字456,b变成Null。 ~~~~~~~~~~ ![使用移动语意赋值。](diagram/move1.png) @@ -304,7 +304,7 @@ Value o(kObjectType); ![复制语意产生大量的复制操作。](diagram/move2.png) -那个`o` Object需要分配一个和contacts相同大小的缓冲区,对conacts做深度复制,并最终要析构contacts。这样会产生大量无必要的内存分配/释放,以及内存复制。 +那个`o` Object需要分配一个和contacts相同大小的缓冲区,对`contacts`做深度复制,并最终要析构`contacts`。这样会产生大量无必要的内存分配/释放,以及内存复制。 有一些方案可避免实质地复制这些数据,例如引用计数(reference counting)、垃圾回收(garbage collection, GC)。 From 44f81f09b4db3c39d2d485f04fb9eb1b07ff661a Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 19 Jan 2016 18:28:28 +0800 Subject: [PATCH 80/98] Remove travis doc job number checking. Travis doc is running on separated task now. --- travis-doxygen.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/travis-doxygen.sh b/travis-doxygen.sh index e9eb6b9..ca4e6e2 100755 --- a/travis-doxygen.sh +++ b/travis-doxygen.sh @@ -42,8 +42,8 @@ abort() { skip "Running Doxygen only for updates on 'master' branch (current: ${TRAVIS_BRANCH})." # check for job number -[ "${TRAVIS_JOB_NUMBER}" = "${TRAVIS_BUILD_NUMBER}.1" ] || \ - skip "Running Doxygen only on first job of build ${TRAVIS_BUILD_NUMBER} (current: ${TRAVIS_JOB_NUMBER})." +#[ "${TRAVIS_JOB_NUMBER}" = "${TRAVIS_BUILD_NUMBER}.1" ] || \ +# skip "Running Doxygen only on first job of build ${TRAVIS_BUILD_NUMBER} (current: ${TRAVIS_JOB_NUMBER})." # install doxygen binary distribution doxygen_install() From ad1d22eba5028a6fef26900f48ea3ae0494d3b75 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 20 Jan 2016 01:53:40 +0800 Subject: [PATCH 81/98] Fix #509 by checking Nan/Inf when writing a double --- include/rapidjson/internal/ieee754.h | 1 + include/rapidjson/writer.h | 8 +++++++- test/unittest/writertest.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h index 6890f89..82bb0b9 100644 --- a/include/rapidjson/internal/ieee754.h +++ b/include/rapidjson/internal/ieee754.h @@ -40,6 +40,7 @@ public: bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index a450456..fab6740 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -139,7 +139,7 @@ public: } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } - + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); @@ -235,6 +235,9 @@ protected: } bool WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) + return false; + char buffer[25]; char* end = internal::dtoa(d, buffer); for (char* p = buffer; p != end; ++p) @@ -381,6 +384,9 @@ inline bool Writer::WriteUint64(uint64_t u) { template<> inline bool Writer::WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) + return false; + char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer); os_->Pop(static_cast(25 - (end - buffer))); diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 2adb551..24a2c6c 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -375,3 +375,27 @@ TEST(Writer, InvalidEventSequence) { EXPECT_FALSE(writer.IsComplete()); } } + +double zero = 0.0; // Use global variable to prevent compiler warning + +TEST(Writer, NaN) { + double nan = zero / zero; + EXPECT_TRUE(internal::Double(nan).IsNan()); + StringBuffer buffer; + Writer writer(buffer); + EXPECT_FALSE(writer.Double(nan)); +} + +TEST(Writer, Inf) { + double inf = 1.0 / zero; + EXPECT_TRUE(internal::Double(inf).IsInf()); + StringBuffer buffer; + { + Writer writer(buffer); + EXPECT_FALSE(writer.Double(inf)); + } + { + Writer writer(buffer); + EXPECT_FALSE(writer.Double(-inf)); + } +} From bab80e7ccae70e11d5782d86cbbba1f93a3e8363 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 20 Jan 2016 02:01:14 +0800 Subject: [PATCH 82/98] Fix clang warning --- test/unittest/writertest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 24a2c6c..197411c 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -376,6 +376,7 @@ TEST(Writer, InvalidEventSequence) { } } +extern double zero; // clang -Wmissing-variable-declarations double zero = 0.0; // Use global variable to prevent compiler warning TEST(Writer, NaN) { From 78c7d54aba2ae0f6639b2539f30ef488d8b877f3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 20 Jan 2016 22:29:50 +0800 Subject: [PATCH 83/98] Fix #498 VC2015 warnings --- include/rapidjson/reader.h | 6 +++--- test/unittest/readertest.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 8628b53..870ed94 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -886,7 +886,7 @@ private: while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { - d = i64; + d = static_cast(i64); useDouble = true; break; } @@ -897,7 +897,7 @@ private: while (s.Peek() >= '0' && s.Peek() <= '9') { if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { - d = i64; + d = static_cast(i64); useDouble = true; break; } @@ -968,7 +968,7 @@ private: int exp = 0; if (s.Peek() == 'e' || s.Peek() == 'E') { if (!useDouble) { - d = use64bit ? i64 : i; + d = static_cast(use64bit ? i64 : i); useDouble = true; } s.Take(); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index f2a0be1..3b84ab7 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -409,7 +409,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) { a = h.actual_; uint64_t bias1 = e.ToBias(); uint64_t bias2 = a.ToBias(); - double ulp = bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1; + double ulp = static_cast(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1); ulpMax = std::max(ulpMax, ulp); ulpSum += ulp; } From 292a5c9d8371569fe5b534f3b768f53835ba1862 Mon Sep 17 00:00:00 2001 From: ReadmeCritic Date: Wed, 20 Jan 2016 11:24:11 -0800 Subject: [PATCH 84/98] Update README URLs based on HTTP redirects --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index fb270fb..9a3d6a7 100644 --- a/readme.md +++ b/readme.md @@ -63,9 +63,9 @@ Users can build and run the unit tests on their platform/compiler. RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. RapidJSON uses following software as its dependencies: -* [CMake](http://www.cmake.org) as a general build tool +* [CMake](https://cmake.org/) as a general build tool * (optional)[Doxygen](http://www.doxygen.org) to build documentation -* (optional)[googletest](https://code.google.com/p/googletest/) for unit and performance testing +* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing To generate user documentation and run tests please proceed with the steps below: From ae5cf58878f3f63a80fcee6e596b07473680b811 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 15:33:08 +0800 Subject: [PATCH 85/98] Fix ScanCopyUnescapedString performance issue --- include/rapidjson/rapidjson.h | 4 ++-- include/rapidjson/reader.h | 17 +++++++++++------ test/perftest/rapidjsontest.cpp | 8 -------- test/unittest/simdtest.cpp | 27 +++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index a90a4a0..0cd9ee7 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -178,9 +178,9 @@ #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && !defined(NDEBUG) +#if defined(_MSC_VER) && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 9ffc68f..924e595 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -800,11 +800,12 @@ private: // Do nothing for generic version } -#if 0 //defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* start = p; const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) { @@ -817,16 +818,17 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); - __m128i x = _mm_cmpeq_epi8(s, dq); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, bs)); - x = _mm_or_si128(x, _mm_cmplt_epi8(s, sp)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; @@ -837,7 +839,10 @@ private: #else length = static_cast(__builtin_ffs(r) - 1); #endif - memcpy(os.Push(length), p, length); + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + p += length; break; } diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 4693755..ad9bba3 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -24,14 +24,6 @@ #include "rapidjson/encodedstream.h" #include "rapidjson/memorystream.h" -#ifdef RAPIDJSON_SSE2 -#define SIMD_SUFFIX(name) name##_SSE2 -#elif defined(RAPIDJSON_SSE42) -#define SIMD_SUFFIX(name) name##_SSE42 -#else -#define SIMD_SUFFIX(name) name -#endif - using namespace rapidjson; class RapidJson : public PerfTest { diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp index 4407c25..963409e 100644 --- a/test/unittest/simdtest.cpp +++ b/test/unittest/simdtest.cpp @@ -66,3 +66,30 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) { TestSkipWhitespace(); TestSkipWhitespace(); } + +template +struct ParseStringHandler : BaseReaderHandler > { + ParseStringHandler() : str_(0), length_(0), copy_() {} + ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } + + ParseStringHandler(const ParseStringHandler&); + ParseStringHandler& operator=(const ParseStringHandler&); + + bool Default() { ADD_FAILURE(); return false; } + bool String(const typename Encoding::Ch* str, size_t length, bool copy) { + EXPECT_EQ(0, str_); + if (copy) { + str_ = static_cast(malloc((length + 1) * sizeof(typename Encoding::Ch))); + memcpy(const_cast(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); + } + else + str_ = str; + length_ = length; + copy_ = copy; + return true; + } + + const typename Encoding::Ch* str_; + size_t length_; + bool copy_; +}; From 6863f7b24c0352fc78cebf6fedb87d68227d5425 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 15:39:07 +0800 Subject: [PATCH 86/98] Fix warning --- include/rapidjson/reader.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 924e595..a629f5b 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -805,7 +805,6 @@ private: const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) - const char* start = p; const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) { From d1e6eae2a91a30c5b4c87eb1f77159a4aa866626 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 15:43:51 +0800 Subject: [PATCH 87/98] Remove unused code --- test/unittest/simdtest.cpp | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp index 963409e..4407c25 100644 --- a/test/unittest/simdtest.cpp +++ b/test/unittest/simdtest.cpp @@ -66,30 +66,3 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) { TestSkipWhitespace(); TestSkipWhitespace(); } - -template -struct ParseStringHandler : BaseReaderHandler > { - ParseStringHandler() : str_(0), length_(0), copy_() {} - ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } - - ParseStringHandler(const ParseStringHandler&); - ParseStringHandler& operator=(const ParseStringHandler&); - - bool Default() { ADD_FAILURE(); return false; } - bool String(const typename Encoding::Ch* str, size_t length, bool copy) { - EXPECT_EQ(0, str_); - if (copy) { - str_ = static_cast(malloc((length + 1) * sizeof(typename Encoding::Ch))); - memcpy(const_cast(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); - } - else - str_ = str; - length_ = length; - copy_ = copy; - return true; - } - - const typename Encoding::Ch* str_; - size_t length_; - bool copy_; -}; From e39265275468dd52a206a10e56f140a01e657263 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 16:05:46 +0800 Subject: [PATCH 88/98] Fix compilation --- test/perftest/rapidjsontest.cpp | 8 ++++++++ test/unittest/readertest.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index ad9bba3..4693755 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -24,6 +24,14 @@ #include "rapidjson/encodedstream.h" #include "rapidjson/memorystream.h" +#ifdef RAPIDJSON_SSE2 +#define SIMD_SUFFIX(name) name##_SSE2 +#elif defined(RAPIDJSON_SSE42) +#define SIMD_SUFFIX(name) name##_SSE42 +#else +#define SIMD_SUFFIX(name) name +#endif + using namespace rapidjson; class RapidJson : public PerfTest { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 6ef1351..c519983 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -417,7 +417,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) { a = h.actual_; uint64_t bias1 = e.ToBias(); uint64_t bias2 = a.ToBias(); - double ulp = bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1; + double ulp = static_cast(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1); ulpMax = std::max(ulpMax, ulp); ulpSum += ulp; } From f13caadded5cd35dec32e77ed7bf7bde0d066dca Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 16:13:06 +0800 Subject: [PATCH 89/98] Fix valgrind problem --- test/unittest/readertest.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index c519983..3b84ab7 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -14,14 +14,6 @@ #include "unittest.h" -// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. -// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported. -#if defined(__SSE4_2__) -# define RAPIDJSON_SSE42 -#elif defined(__SSE2__) -# define RAPIDJSON_SSE2 -#endif - #include "rapidjson/reader.h" #include "rapidjson/internal/dtoa.h" #include "rapidjson/internal/itoa.h" From a5990f3eea871e4390c93da95f850d762c372605 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 18:26:24 +0800 Subject: [PATCH 90/98] Optimize ScanCopyUnescapedString for insitu parsing --- include/rapidjson/reader.h | 110 ++++++++++++++++++++++++++++++-- test/perftest/perftest.h | 9 +-- test/perftest/rapidjsontest.cpp | 9 +++ 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index a629f5b..3930808 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -705,6 +705,9 @@ private: internal::StreamLocalCopy copy(is); InputStream& s(copy.s); + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); @@ -743,9 +746,6 @@ private: #undef Z16 //!@endcond - RAPIDJSON_ASSERT(is.Peek() == '\"'); - is.Take(); // Skip '\"' - for (;;) { // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. if (!(parseFlags & kParseValidateEncodingFlag)) @@ -801,13 +801,14 @@ private: } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) { + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; return; } @@ -850,6 +851,107 @@ private: is.src_ = p; } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + goto exit; + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char* pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + +exit: + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + bool found = false; + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + goto exit; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + exit: + is.src_ = is.dst_ = p; + } #endif template diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index 2afe641..0d31602 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -135,11 +135,11 @@ public: sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]); if (FILE* fp = fopen(filename, "rb")) { fseek(fp, 0, SEEK_END); - size_t length = (size_t)ftell(fp); + typesLength_[j] = (size_t)ftell(fp); fseek(fp, 0, SEEK_SET); - types_[j] = (char*)malloc(length + 1); - ASSERT_EQ(length, fread(types_[j], 1, length, fp)); - types_[j][length] = '\0'; + types_[j] = (char*)malloc(typesLength_[j] + 1); + ASSERT_EQ(typesLength_[j], fread(types_[j], 1, typesLength_[j], fp)); + types_[j][typesLength_[j]] = '\0'; fclose(fp); break; } @@ -170,6 +170,7 @@ protected: char *whitespace_; size_t whitespace_length_; char *types_[7]; + size_t typesLength_[7]; static const size_t kTrialCount = 1000; }; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 4693755..7f5fc08 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -103,6 +103,15 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_##Name)) {\ Reader reader;\ EXPECT_TRUE(reader.Parse(s, h));\ }\ +}\ +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_##Name)) {\ + for (size_t i = 0; i < kTrialCount * 10; i++) {\ + memcpy(temp_, types_[index], typesLength_[index] + 1);\ + InsituStringStream s(temp_);\ + BaseReaderHandler<> h;\ + Reader reader;\ + EXPECT_TRUE(reader.Parse(s, h));\ + }\ } TEST_TYPED(0, Booleans) From 4f4aff329fb41f2a00fe56400107b43ee2ec0c79 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 18:33:08 +0800 Subject: [PATCH 91/98] Fix clang compilation --- include/rapidjson/reader.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 3930808..6022e50 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -855,6 +855,7 @@ private: // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); + (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); @@ -867,8 +868,11 @@ private: // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) - goto exit; + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } else *q++ = *p++; @@ -903,7 +907,6 @@ private: _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); } -exit: is.src_ = p; is.dst_ = q; } @@ -915,10 +918,11 @@ exit: // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); - bool found = false; for (; p != nextAligned; p++) - if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) - goto exit; + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; @@ -949,7 +953,6 @@ exit: } } - exit: is.src_ = is.dst_ = p; } #endif From a202d82339c4e52ab9522eef230dd80b93615333 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 18:42:50 +0800 Subject: [PATCH 92/98] Make whitespace array more compact --- include/rapidjson/reader.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 6022e50..3911ff2 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -314,16 +314,14 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // The rest of string - static const char whitespaces[4][17] = { - " ", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 - const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); - const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); - const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); - const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); From f183282b64f78df44f54b61d7d8c7d0d7db537f3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 22 Jan 2016 19:03:00 +0800 Subject: [PATCH 93/98] Fix warning --- include/rapidjson/reader.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 6022e50..cd37a27 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -680,7 +680,7 @@ private: ++length_; } - RAPIDJSON_FORCEINLINE void* Push(size_t count) { + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push(count); } @@ -831,13 +831,13 @@ private: const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped - size_t length; + SizeType length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else - length = static_cast(__builtin_ffs(r) - 1); + length = static_cast(__builtin_ffs(r) - 1); #endif char* q = reinterpret_cast(os.Push(length)); for (size_t i = 0; i < length; i++) From a6eb15d274fbf0f8f6e0049c244f48fc476ddb5a Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Jan 2016 14:37:15 +0800 Subject: [PATCH 94/98] Fix warnings in clang for C++11 --- CMakeLists.txt | 8 +++++ example/serialize/serialize.cpp | 3 ++ include/rapidjson/document.h | 4 +-- include/rapidjson/internal/stack.h | 9 ++++++ include/rapidjson/internal/swap.h | 9 ++++++ include/rapidjson/stringbuffer.h | 9 ++++++ test/unittest/documenttest.cpp | 10 +++++++ test/unittest/readertest.cpp | 1 + test/unittest/stringbuffertest.cpp | 9 ++++++ test/unittest/unittest.cpp | 11 +++++++ test/unittest/unittest.h | 12 ++++++++ test/unittest/valuetest.cpp | 47 ++++++++++++++++++++++++------ 12 files changed, 121 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51ee620..5971bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON) option(RAPIDJSON_BUILD_THIRDPARTY_GTEST "Use gtest installation in `thirdparty/gtest` by default if available" OFF) +option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON) + option(RAPIDJSON_HAS_STDSTRING "" OFF) if(RAPIDJSON_HAS_STDSTRING) add_definitions(-DRAPIDJSON_HAS_STDSTRING) @@ -27,8 +29,14 @@ endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") + if (RAPIDJSON_BUILD_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers") + if (RAPIDJSON_BUILD_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/example/serialize/serialize.cpp b/example/serialize/serialize.cpp index 6c5e5c2..cef5c66 100644 --- a/example/serialize/serialize.cpp +++ b/example/serialize/serialize.cpp @@ -11,6 +11,7 @@ using namespace rapidjson; class Person { public: Person(const std::string& name, unsigned age) : name_(name), age_(age) {} + Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {} virtual ~Person(); protected: @@ -38,6 +39,7 @@ Person::~Person() { class Education { public: Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {} + Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {} template void Serialize(Writer& writer) const { @@ -102,6 +104,7 @@ Dependent::~Dependent() { class Employee : public Person { public: Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {} + Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {} virtual ~Employee(); void AddDependent(const Dependent& dependent) { diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 095aa40..12187ea 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -31,6 +31,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(c++98-compat) #endif #ifdef __GNUC__ @@ -141,6 +142,7 @@ public: Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } //! @name stepping //@{ @@ -314,8 +316,6 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: - //! Disallow copy-assignment - GenericStringRef operator=(const GenericStringRef&); //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 3d691d3..12f8a8f 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -18,6 +18,11 @@ #include "../rapidjson.h" #include "swap.h" +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -203,4 +208,8 @@ private: } // namespace internal RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_STACK_H_ diff --git a/include/rapidjson/internal/swap.h b/include/rapidjson/internal/swap.h index 39bc2e4..cbb2abd 100644 --- a/include/rapidjson/internal/swap.h +++ b/include/rapidjson/internal/swap.h @@ -17,6 +17,11 @@ #include "../rapidjson.h" +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -34,4 +39,8 @@ inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { } // namespace internal RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h index 40b51cd..0d32859 100644 --- a/include/rapidjson/stringbuffer.h +++ b/include/rapidjson/stringbuffer.h @@ -23,6 +23,11 @@ #include "internal/stack.h" +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. @@ -103,4 +108,8 @@ inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index cdc4c31..c3438f3 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -21,6 +21,12 @@ #include #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +RAPIDJSON_DIAG_OFF(missing-variable-declarations) +#endif + using namespace rapidjson; template @@ -573,3 +579,7 @@ TYPED_TEST(DocumentMove, MoveAssignmentStack) { // Document d2; // d1 = d2; //} + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 3b84ab7..49888a9 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -31,6 +31,7 @@ RAPIDJSON_DIAG_OFF(missing-noreturn) #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(variadic-macros) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) #endif template diff --git a/test/unittest/stringbuffertest.cpp b/test/unittest/stringbuffertest.cpp index fbacf51..28fdbc5 100644 --- a/test/unittest/stringbuffertest.cpp +++ b/test/unittest/stringbuffertest.cpp @@ -16,6 +16,11 @@ #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + using namespace rapidjson; TEST(StringBuffer, InitialSize) { @@ -148,3 +153,7 @@ TEST(StringBuffer, MoveAssignment) { } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif diff --git a/test/unittest/unittest.cpp b/test/unittest/unittest.cpp index dd562a2..655518a 100644 --- a/test/unittest/unittest.cpp +++ b/test/unittest/unittest.cpp @@ -15,8 +15,19 @@ #include "unittest.h" #include "rapidjson/rapidjson.h" +#ifdef __clang__ +#pragma GCC diagnostic push +#if __has_warning("-Wdeprecated") +#pragma GCC diagnostic ignored "-Wdeprecated" +#endif +#endif + AssertException::~AssertException() throw() {} +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 6062410..60e6c18 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -99,12 +99,24 @@ inline FILE* TempFile(char *filename) { #pragma warning(disable : 4127) #endif +#ifdef __clang__ +#pragma GCC diagnostic push +#if __has_warning("-Wdeprecated") +#pragma GCC diagnostic ignored "-Wdeprecated" +#endif +#endif + class AssertException : public std::logic_error { public: AssertException(const char* w) : std::logic_error(w) {} + AssertException(const AssertException& rhs) : std::logic_error(rhs) {} virtual ~AssertException() throw(); }; +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif + #define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x)) class Random { diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 245ccac..b2963fc 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -16,6 +16,11 @@ #include "rapidjson/document.h" #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + using namespace rapidjson; TEST(Value, DefaultConstructor) { @@ -764,15 +769,15 @@ TEST(Value, Array) { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS // PushBack(GenericValue&&, Allocator&); { - Value y(kArrayType); - y.PushBack(Value(true), allocator); - y.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator); - EXPECT_EQ(2u, y.Size()); - EXPECT_TRUE(y[0].IsTrue()); - EXPECT_TRUE(y[1].IsArray()); - EXPECT_EQ(2u, y[1].Size()); - EXPECT_TRUE(y[1][0].IsInt()); - EXPECT_TRUE(y[1][1].IsString()); + Value y2(kArrayType); + y2.PushBack(Value(true), allocator); + y2.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator); + EXPECT_EQ(2u, y2.Size()); + EXPECT_TRUE(y2[0].IsTrue()); + EXPECT_TRUE(y2[1].IsArray()); + EXPECT_EQ(2u, y2[1].Size()); + EXPECT_TRUE(y2[1][0].IsInt()); + EXPECT_TRUE(y2[1][1].IsString()); } #endif @@ -1354,3 +1359,27 @@ TEST(Value, AcceptTerminationByHandler) { TEST_TERMINATION(11, "{\"a\":[]}"); TEST_TERMINATION(12, "{\"a\":[]}"); } + +struct ValueIntComparer { + bool operator()(const Value& lhs, const Value& rhs) const { + return lhs.GetInt() < rhs.GetInt(); + } +}; + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +TEST(Value, Sorting) { + Value::AllocatorType allocator; + Value a(kArrayType); + a.PushBack(5, allocator); + a.PushBack(1, allocator); + a.PushBack(3, allocator); + std::sort(a.Begin(), a.End(), ValueIntComparer()); + EXPECT_EQ(1, a[0].GetInt()); + EXPECT_EQ(3, a[1].GetInt()); + EXPECT_EQ(5, a[2].GetInt()); +} +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif From 2f5a69b2fb7ed305a0de0a8d7bacc63c1dfeb0b3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Jan 2016 14:58:19 +0800 Subject: [PATCH 95/98] Try using c++0x for gcc 4.6.x --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5971bb7..33f3ef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,11 @@ endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror") if (RAPIDJSON_BUILD_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers") From d8c793f23f1b092638f464528789a6c1f4b57c44 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Jan 2016 15:27:59 +0800 Subject: [PATCH 96/98] Disable type_traits --- test/unittest/documenttest.cpp | 4 ++++ test/unittest/stringbuffertest.cpp | 4 ++++ test/unittest/valuetest.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index c3438f3..1b1c469 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -334,6 +334,8 @@ TEST(Document, UTF16_Document) { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if 0 // Many old compiler does not support these. Turn it off temporaily. + #include TEST(Document, Traits) { @@ -371,6 +373,8 @@ TEST(Document, Traits) { #endif } +#endif + template struct DocumentMove: public ::testing::Test { }; diff --git a/test/unittest/stringbuffertest.cpp b/test/unittest/stringbuffertest.cpp index 28fdbc5..9be98fc 100644 --- a/test/unittest/stringbuffertest.cpp +++ b/test/unittest/stringbuffertest.cpp @@ -74,6 +74,8 @@ TEST(StringBuffer, Pop) { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if 0 // Many old compiler does not support these. Turn it off temporaily. + #include TEST(StringBuffer, Traits) { @@ -111,6 +113,8 @@ TEST(StringBuffer, Traits) { #endif } +#endif + TEST(StringBuffer, MoveConstructor) { StringBuffer x; x.Put('A'); diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index b2963fc..5cecdc7 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -39,6 +39,8 @@ TEST(Value, DefaultConstructor) { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if 0 // Many old compiler does not support these. Turn it off temporaily. + #include TEST(Value, Traits) { @@ -77,6 +79,8 @@ TEST(Value, Traits) { #endif } +#endif + TEST(Value, MoveConstructor) { typedef GenericValue, CrtAllocator> Value; Value::AllocatorType allocator; From a7490404ba1e323673297765484b8ec7e7431bec Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Jan 2016 15:38:01 +0800 Subject: [PATCH 97/98] Try to fix a clang missing assignment warning --- example/serialize/serialize.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/example/serialize/serialize.cpp b/example/serialize/serialize.cpp index cef5c66..a7f330e 100644 --- a/example/serialize/serialize.cpp +++ b/example/serialize/serialize.cpp @@ -14,6 +14,12 @@ public: Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {} virtual ~Person(); + Person& operator=(const Person& rhs) { + name_ = rhs.name_; + age_ = rhs.age_; + return *this; + } + protected: template void Serialize(Writer& writer) const { @@ -107,6 +113,13 @@ public: Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {} virtual ~Employee(); + Employee& operator=(const Employee& rhs) { + static_cast(*this) = rhs; + dependents_ = rhs.dependents_; + married_ = rhs.married_; + return *this; + } + void AddDependent(const Dependent& dependent) { dependents_.push_back(dependent); } From 403115019b26b92e146dd0174438e8c79c688cdd Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Jan 2016 15:53:27 +0800 Subject: [PATCH 98/98] Add travis C++11 on/off matrix --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index be06f35..78fe1d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,12 @@ compiler: env: matrix: - - CONF=debug ARCH=x86_64 - - CONF=release ARCH=x86_64 - - CONF=debug ARCH=x86 - - CONF=release ARCH=x86 + - CONF=debug ARCH=x86_64 CXX11=ON + - CONF=release ARCH=x86_64 CXX11=ON + - CONF=debug ARCH=x86 CXX11=ON + - CONF=release ARCH=x86 CXX11=ON + - CONF=debug ARCH=x86_64 CXX11=OFF + - CONF=debug ARCH=x86 CXX11=OFF global: - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit @@ -34,6 +36,7 @@ before_script: eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ; (cd build && cmake -DRAPIDJSON_HAS_STDSTRING=ON + -DRAPIDJSON_BUILD_CXX11=$CXX11 -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=$CONF -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"