From 595b114216f8899eb72695394bff9cb5856313e6 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Mon, 27 Feb 2017 22:36:48 -0800 Subject: [PATCH 01/20] Unit test Add unit tests expecting an assertion when writing an object with a key but no value. --- test/unittest/writertest.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index d346e0f..398a63d 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -442,6 +442,28 @@ TEST(Writer, InvalidEventSequence) { EXPECT_THROW(writer.Int(1), AssertException); EXPECT_FALSE(writer.IsComplete()); } + + // { 'a' } + { + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + writer.Key("a"); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // { 'a':'b','c' } + { + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + writer.Key("a"); + writer.String("b"); + writer.Key("c"); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } } TEST(Writer, NaN) { From 2e9b7b1ae6ef162b5aa0c04f2b4444be4c8b72cb Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Mon, 27 Feb 2017 22:44:13 -0800 Subject: [PATCH 02/20] Added assertion Documented existing assertions in EndObject Added new assertion in EndObject to catch error condition where objects are ended with a key but no matching value. --- include/rapidjson/writer.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 5b3004b..43ec5dc 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -221,8 +221,9 @@ public: bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop(1); return EndValue(WriteEndObject()); } From fa84cd18f48294dc94f659c3f7a272b26ea5b1b5 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Mon, 27 Feb 2017 22:53:59 -0800 Subject: [PATCH 03/20] Add matching fix for PrettyWriter PrettyWriter EndObject will now also assert if called when a key is missing its matching value. --- include/rapidjson/prettywriter.h | 6 ++-- test/unittest/prettywritertest.cpp | 51 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index d663208..b68b687 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -136,8 +136,10 @@ public: bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp index 13d1a8d..2891c76 100644 --- a/test/unittest/prettywritertest.cpp +++ b/test/unittest/prettywritertest.cpp @@ -207,6 +207,57 @@ TEST(PrettyWriter, RawValue) { buffer.GetString()); } +TEST(PrettyWriter, InvalidEventSequence) { + // {] + { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartObject(); + EXPECT_THROW(writer.EndArray(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // [} + { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartArray(); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // { 1: + { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartObject(); + EXPECT_THROW(writer.Int(1), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // { 'a' } + { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartObject(); + writer.Key("a"); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // { 'a':'b','c' } + { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartObject(); + writer.Key("a"); + writer.String("b"); + writer.Key("c"); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } +} + #if RAPIDJSON_HAS_CXX11_RVALUE_REFS static PrettyWriter WriterGen(StringBuffer &target) { From 0ec4e86f14a0b801cee4a707f51245a6b735fef2 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Mon, 27 Feb 2017 23:06:05 -0800 Subject: [PATCH 04/20] Unit test Add unit test for Issue 848 (segfault in ~Document) --- test/unittest/schematest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 4780516..30b3260 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -1281,6 +1281,12 @@ TEST(SchemaValidatingWriter, Simple) { EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType("")); } +TEST(Schema, Issue848) { + rapidjson::Document d; + rapidjson::SchemaDocument s(d); + rapidjson::GenericSchemaValidator v(s); +} + #if RAPIDJSON_HAS_CXX11_RVALUE_REFS static SchemaDocument ReturnSchemaDocument() { From 4643104b8a0424f8f645b2777fbcdccf9a17acbf Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Mon, 27 Feb 2017 23:28:25 -0800 Subject: [PATCH 05/20] Fix null handler construction We should not malloc the null-handler object and cast to OutputHandler; we need to actually invoke the constructor via placement new. --- include/rapidjson/schema.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index c20a838..3dddd3a 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1928,7 +1928,7 @@ private: const Context& CurrentContext() const { return *schemaStack_.template Top(); } OutputHandler& CreateNullHandler() { - return *(nullHandler_ = static_cast(GetStateAllocator().Malloc(sizeof(OutputHandler)))); + return *(nullHandler_ = new (GetStateAllocator().Malloc(sizeof(OutputHandler))) OutputHandler); } static const size_t kDefaultSchemaStackCapacity = 1024; From 5c2bb187725f27de73cb1ca8b26750e0e139046b Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Tue, 28 Feb 2017 00:06:02 -0800 Subject: [PATCH 06/20] Add IterativeParse docs --- doc/sax.md | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/doc/sax.md b/doc/sax.md index ed6d46a..c716d3a 100644 --- a/doc/sax.md +++ b/doc/sax.md @@ -8,7 +8,7 @@ In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style parser # Reader {#Reader} -`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyze the characters according to the syntax of JSON, and publish events to a handler. +`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyzes the characters according to the syntax of JSON, and publishes events to a handler. For example, here is a JSON. @@ -24,7 +24,7 @@ For example, here is a JSON. } ~~~~~~~~~~ -While a `Reader` parses this JSON, it publishes the following events to the handler sequentially: +When a `Reader` parses this JSON, it publishes the following events to the handler sequentially: ~~~~~~~~~~ StartObject() @@ -50,7 +50,7 @@ EndArray(4) EndObject(7) ~~~~~~~~~~ -These events can be easily matched with the JSON, except some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above: +These events can be easily matched with the JSON, but some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above: ~~~~~~~~~~cpp #include "rapidjson/reader.h" @@ -91,11 +91,11 @@ void main() { } ~~~~~~~~~~ -Note that, RapidJSON uses template to statically bind the `Reader` type and the handler type, instead of using class with virtual functions. This paradigm can improve the performance by inlining functions. +Note that RapidJSON uses templates to statically bind the `Reader` type and the handler type, instead of using classes with virtual functions. This paradigm can improve performance by inlining functions. ## Handler {#Handler} -As the previous example showed, user needs to implement a handler, which consumes the events (function calls) from `Reader`. The handler must contain the following member functions. +As shown in the previous example, the user needs to implement a handler which consumes the events (via function calls) from the `Reader`. The handler must contain the following member functions. ~~~~~~~~~~cpp class Handler { @@ -122,15 +122,15 @@ class Handler { When the `Reader` encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, `Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`. If `kParseNumbersAsStrings` is enabled, `Reader` will always calls `RawNumber()` instead. -`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `\0` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And beware that, the character type depends on the target encoding, which will be explained later. +`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `\0` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And be aware that the character type depends on the target encoding, which will be explained later. -When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeats until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler, user may not need this parameter. +When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it. -Array is similar to object but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. +Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. -Every handler functions returns a `bool`. Normally it should returns `true`. If the handler encounters an error, it can return `false` to notify event publisher to stop further processing. +Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing. -For example, when we parse a JSON with `Reader` and the handler detected that the JSON does not conform to the required schema, then the handler can return `false` and let the `Reader` stop further parsing. And the `Reader` will be in error state with error code `kParseErrorTermination`. +For example, when we parse a JSON with `Reader` and the handler detects that the JSON does not conform to the required schema, the handler can return `false` and let the `Reader` stop further parsing. This will place the `Reader` in an error state, with error code `kParseErrorTermination`. ## GenericReader {#GenericReader} @@ -149,19 +149,19 @@ typedef GenericReader, UTF8<> > Reader; } // namespace rapidjson ~~~~~~~~~~ -The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and outputs UTF-16 string events, you can define a reader by: +The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and output UTF-16 string events, you can define a reader by: ~~~~~~~~~~cpp GenericReader, UTF16<> > reader; ~~~~~~~~~~ -Note that, the default character type of `UTF16` is `wchar_t`. So this `reader`needs to call `String(const wchar_t*, SizeType, bool)` of the handler. +Note that, the default character type of `UTF16` is `wchar_t`. So this `reader` needs to call `String(const wchar_t*, SizeType, bool)` of the handler. The third template parameter `Allocator` is the allocator type for internal data structure (actually a stack). ## Parsing {#SaxParsing} -The one and only one function of `Reader` is to parse JSON. +The main function of `Reader` is used to parse JSON. ~~~~~~~~~~cpp template @@ -172,7 +172,30 @@ template bool Parse(InputStream& is, Handler& handler); ~~~~~~~~~~ -If an error occurs during parsing, it will return `false`. User can also calls `bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. Actually `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse error. +If an error occurs during parsing, it will return `false`. User can also call `bool HasParseError()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. In fact, `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse errors. + +## Token-by-Token Parsing {#TokenByTokenParsing} + +Some users may wish to parse a JSON input stream a single token at a time, instead of immediately parsing an entire document without stopping. To parse JSON this way, instead of calling `Parse`, you can use the `IterativeParse` set of functions: + +~~~~~~~~~~cpp + void IterativeParseInit(); + + template + bool IterativeParseNext(InputStream& is, Handler& handler); + + bool IterativeParseComplete(); +~~~~~~~~~~ + +Here is an example of iteratively parsing JSON, token by token: + +~~~~~~~~~~cpp + reader.IterativeParseInit(); + while (!reader.IterativeParseComplete()) { + reader.IterativeParseNext(ss, handler); + // Your handler has been called once. + } +~~~~~~~~~~ # Writer {#Writer} From 0f3bf99d58a4d704246c1bba6183838629960abd Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Tue, 28 Feb 2017 00:08:30 -0800 Subject: [PATCH 07/20] Tiny fix Make example code var names match API above for consistency --- doc/sax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sax.md b/doc/sax.md index c716d3a..4867880 100644 --- a/doc/sax.md +++ b/doc/sax.md @@ -192,7 +192,7 @@ Here is an example of iteratively parsing JSON, token by token: ~~~~~~~~~~cpp reader.IterativeParseInit(); while (!reader.IterativeParseComplete()) { - reader.IterativeParseNext(ss, handler); + reader.IterativeParseNext(is, handler); // Your handler has been called once. } ~~~~~~~~~~ From 6e2e5c7dbe08474249ca18b50da120b2c45ccc36 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Tue, 28 Feb 2017 01:11:30 -0800 Subject: [PATCH 08/20] Specialize StrLen for char/wchar_t Compilers generally provide a much smarter strlen than ours. --- include/rapidjson/internal/strfunc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/rapidjson/internal/strfunc.h b/include/rapidjson/internal/strfunc.h index de41d8f..226439a 100644 --- a/include/rapidjson/internal/strfunc.h +++ b/include/rapidjson/internal/strfunc.h @@ -16,6 +16,7 @@ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" +#include RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -34,6 +35,16 @@ inline SizeType StrLen(const Ch* s) { return SizeType(p - s); } +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + //! Returns number of code points in a encoded string. template bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { From 4b822a41af98974a4ca96b79cd13afe163214d81 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Tue, 28 Feb 2017 19:31:21 -0800 Subject: [PATCH 09/20] Attempt to suppress valgrind wcslen error --- test/unittest/CMakeLists.txt | 2 +- test/valgrind.supp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 test/valgrind.supp diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 4e29765..fdf0ad0 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -79,7 +79,7 @@ add_test(NAME unittest if(NOT MSVC) # Not running SIMD.* unit test cases for Valgrind add_test(NAME valgrind_unittest - COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.* + COMMAND valgrind --suppressions=${CMAKE_SOURCE_DIR}/test/valgrind.supp --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.* WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/test/valgrind.supp b/test/valgrind.supp new file mode 100644 index 0000000..5a205b7 --- /dev/null +++ b/test/valgrind.supp @@ -0,0 +1,5 @@ +{ + Suppress wcslen valgrind report + Memcheck:Addr8 + fun:__wcslen_sse2 +} From 13e99d8d5ffea627a169734128d38a31a7895b29 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Tue, 28 Feb 2017 22:58:24 -0800 Subject: [PATCH 10/20] Trivial change to re-trigger Travis CI No-op blank line --- test/unittest/writertest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 398a63d..8fd6eb8 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -544,3 +544,4 @@ TEST(Writer, MoveCtor) { #ifdef __clang__ RAPIDJSON_DIAG_POP #endif + From 3f9ebfe9e9e9b4ac57f8d58fbce390b4f9a5977e Mon Sep 17 00:00:00 2001 From: John Stiles Date: Thu, 2 Mar 2017 21:24:03 -0800 Subject: [PATCH 11/20] Trivial change to trigger Travis CI --- include/rapidjson/writer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 43ec5dc..12d3145 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -623,3 +623,4 @@ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ + From 534f1352619328668e8bc4ffaf9bacb5de697180 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Fri, 3 Mar 2017 00:21:10 -0800 Subject: [PATCH 12/20] Try again to suppress Valgrind --- test/valgrind.supp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/valgrind.supp b/test/valgrind.supp index 5a205b7..8552385 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -1,5 +1,5 @@ { Suppress wcslen valgrind report - Memcheck:Addr8 + Memcheck:Cond fun:__wcslen_sse2 } From 6ae50ad6e32030c2d930b313a1c740acbbb0cca6 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Fri, 3 Mar 2017 00:27:47 -0800 Subject: [PATCH 13/20] Once again --- test/valgrind.supp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/valgrind.supp b/test/valgrind.supp index 8552385..1fed18b 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -1,5 +1,17 @@ { - Suppress wcslen valgrind report + Suppress wcslen valgrind report 1 Memcheck:Cond fun:__wcslen_sse2 } + +{ + Suppress wcslen valgrind report 2 + Memcheck:Addr8 + fun:__wcslen_sse2 +} + +{ + Suppress wcslen valgrind report 3 + Memcheck:Value8 + fun:__wcslen_sse2 +} From db8d3bb4d60aa20c5d6ec4be1f6e71c33d9874b9 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Fri, 3 Mar 2017 00:42:00 -0800 Subject: [PATCH 14/20] Remove unneeded change --- include/rapidjson/writer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 12d3145..43ec5dc 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -623,4 +623,3 @@ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ - From 66b564f385d96d7adbe1ba3073a140f5301e0af6 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Fri, 3 Mar 2017 00:42:21 -0800 Subject: [PATCH 15/20] Remove unneeded change --- test/unittest/writertest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 8fd6eb8..398a63d 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -544,4 +544,3 @@ TEST(Writer, MoveCtor) { #ifdef __clang__ RAPIDJSON_DIAG_POP #endif - From d6e9cf5d54ee40dcbe4cc939f33cdf41878a71d7 Mon Sep 17 00:00:00 2001 From: Erik Froseth Date: Fri, 3 Mar 2017 09:48:41 +0100 Subject: [PATCH 16/20] Remove executable bit Remove the executable bit for various .json files --- bin/types/booleans.json | Bin bin/types/floats.json | Bin bin/types/guids.json | Bin bin/types/integers.json | Bin bin/types/mixed.json | Bin bin/types/nulls.json | Bin bin/types/paragraphs.json | Bin 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bin/types/booleans.json mode change 100755 => 100644 bin/types/floats.json mode change 100755 => 100644 bin/types/guids.json mode change 100755 => 100644 bin/types/integers.json mode change 100755 => 100644 bin/types/mixed.json mode change 100755 => 100644 bin/types/nulls.json mode change 100755 => 100644 bin/types/paragraphs.json diff --git a/bin/types/booleans.json b/bin/types/booleans.json old mode 100755 new mode 100644 diff --git a/bin/types/floats.json b/bin/types/floats.json old mode 100755 new mode 100644 diff --git a/bin/types/guids.json b/bin/types/guids.json old mode 100755 new mode 100644 diff --git a/bin/types/integers.json b/bin/types/integers.json old mode 100755 new mode 100644 diff --git a/bin/types/mixed.json b/bin/types/mixed.json old mode 100755 new mode 100644 diff --git a/bin/types/nulls.json b/bin/types/nulls.json old mode 100755 new mode 100644 diff --git a/bin/types/paragraphs.json b/bin/types/paragraphs.json old mode 100755 new mode 100644 From dd97ede84d517e2a1d433c5bfc1610d5d769a430 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Sun, 5 Mar 2017 00:27:08 -0800 Subject: [PATCH 17/20] Quoted strings to String() or Key() are auto-sized by template No strlen call needs to be made when templates can auto-deduce the string length. No strlen = faster! Unfortunately this needs a touch of SFINAE to allow multiple overrides to coexist cleanly. --- include/rapidjson/writer.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 43ec5dc..755f483 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -16,6 +16,7 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" @@ -198,7 +199,8 @@ public: return EndValue(WriteString(str, length)); } - bool String(const Ch* str, SizeType length, bool copy = false) { + template + bool String(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); @@ -217,7 +219,8 @@ public: return WriteStartObject(); } - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + template + bool Key(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, length, copy); } bool EndObject(SizeType memberCount = 0) { (void)memberCount; @@ -247,8 +250,16 @@ public: //@{ //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + template + bool String(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, internal::StrLen(str)); } + template + bool Key(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, internal::StrLen(str)); } + + //! The compiler can give us the length of quoted strings for free. + template + bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, N-1); } + template + bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, N-1); } //@} From 61f8c4ef0df9d91fe6a684bb1b1572e0a537f66e Mon Sep 17 00:00:00 2001 From: John Stiles Date: Sun, 5 Mar 2017 00:38:34 -0800 Subject: [PATCH 18/20] Quoted strings to String() or Key() are auto-sized by template Same fix as previous commit, to prettywriter --- include/rapidjson/prettywriter.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index b68b687..64301b8 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -107,7 +107,8 @@ public: return Base::WriteString(str, length); } - bool String(const Ch* str, SizeType length, bool copy = false) { + template + bool String(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); @@ -126,7 +127,8 @@ public: return Base::WriteStartObject(); } - bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + template + bool Key(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { @@ -184,8 +186,16 @@ public: //@{ //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + template + bool String(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, internal::StrLen(str)); } + template + bool Key(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, internal::StrLen(str)); } + + //! The compiler can give us the length of quoted strings for free. + template + bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, N-1); } + template + bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, N-1); } //@} From cdea825a0bc81531d2cd2758362b606106373477 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Sun, 5 Mar 2017 09:23:03 -0800 Subject: [PATCH 19/20] Assert that String() and Key() are given null-terminated strings Assert in case users attempt to pass a char array to String() or Key() that is not null terminated; that is not the intended use of the API. Null terminate your string buffers. --- include/rapidjson/prettywriter.h | 10 ++++++++-- include/rapidjson/writer.h | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 64301b8..abea404 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -193,9 +193,15 @@ public: //! The compiler can give us the length of quoted strings for free. template - bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, N-1); } + bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) + return String(str, N-1); + } template - bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, N-1); } + bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) + return Key(str, N-1); + } //@} diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 755f483..c438f71 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -257,9 +257,15 @@ public: //! The compiler can give us the length of quoted strings for free. template - bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, N-1); } + bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) + return String(str, N-1); + } template - bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, N-1); } + bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) + return Key(str, N-1); + } //@} From c4e3d6243ce0321b32c9bfc7e3692753b21e46f8 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Sun, 5 Mar 2017 09:50:03 -0800 Subject: [PATCH 20/20] Fix msvc x64 compilation issue Disambiguate by putting the ENABLEIF on the return value instead of in the argument list. --- include/rapidjson/prettywriter.h | 12 ++++++------ include/rapidjson/writer.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index abea404..a9d0f02 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -108,7 +108,7 @@ public: } template - bool String(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); @@ -128,7 +128,7 @@ public: } template - bool Key(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, length, copy); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { @@ -187,18 +187,18 @@ public: //! Simpler but slower overload. template - bool String(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, internal::StrLen(str)); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T* const& str) { return String(str, internal::StrLen(str)); } template - bool Key(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, internal::StrLen(str)); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T* const& str) { return Key(str, internal::StrLen(str)); } //! The compiler can give us the length of quoted strings for free. template - bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T (&str)[N]) { RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) return String(str, N-1); } template - bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T (&str)[N]) { RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) return Key(str, N-1); } diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index c438f71..7a0af39 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -200,7 +200,7 @@ public: } template - bool String(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); @@ -220,7 +220,7 @@ public: } template - bool Key(const T* str, SizeType length, bool copy = false, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, length, copy); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool EndObject(SizeType memberCount = 0) { (void)memberCount; @@ -251,18 +251,18 @@ public: //! Simpler but slower overload. template - bool String(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return String(str, internal::StrLen(str)); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T* const& str) { return String(str, internal::StrLen(str)); } template - bool Key(const T* const& str, RAPIDJSON_ENABLEIF((internal::IsSame))) { return Key(str, internal::StrLen(str)); } + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T* const& str) { return Key(str, internal::StrLen(str)); } //! The compiler can give us the length of quoted strings for free. template - bool String(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) String(const T (&str)[N]) { RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) return String(str, N-1); } template - bool Key(const T (&str)[N], RAPIDJSON_ENABLEIF((internal::IsSame))) { + RAPIDJSON_ENABLEIF_RETURN((internal::IsSame), (bool)) Key(const T (&str)[N]) { RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated) return Key(str, N-1); }