From 0691502573f1afd3341073dd24b12c3db20fbde4 Mon Sep 17 00:00:00 2001 From: miloyip Date: Sun, 10 May 2015 22:54:47 +0800 Subject: [PATCH 1/9] Fix MemoryPoolAllocator::Clear() to clear user-buffer --- include/rapidjson/allocators.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index b7042a53c..f615ffd99 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -143,11 +143,13 @@ class MemoryPoolAllocator { //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { - while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { + while (chunkHead_ && chunkHead_ != userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer } //! Computes the total capacity of allocated memory chunks. From ffbe38614732af8e0b3abdc8b50071f386a4a685 Mon Sep 17 00:00:00 2001 From: miloyip Date: Sun, 10 May 2015 23:26:58 +0800 Subject: [PATCH 2/9] Change Document::ParseStream() to use stack allocator for Reader --- 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 738677332..aab489c05 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1741,7 +1741,7 @@ class GenericDocument : public GenericValue { template GenericDocument& ParseStream(InputStream& is) { ValueType::SetNull(); // Remove existing root if exist - GenericReader reader(&GetAllocator()); + GenericReader reader(&stack_.GetAllocator()); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { From 91a7e01c1e348302ce31ada5aec7167c50545c96 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 11 May 2015 11:03:50 +0800 Subject: [PATCH 3/9] Fix Document.UserBuffer test --- test/unittest/documenttest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 940b2958b..2ee6b1039 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -241,7 +241,7 @@ TEST(Document, UserBuffer) { char parseBuffer[1024]; MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer)); MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer)); - DocumentType doc(&valueAllocator, sizeof(parseBuffer), &parseAllocator); + DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator); doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); EXPECT_FALSE(doc.HasParseError()); EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer)); From de55114f97c923967f0b1c834bf94291d8cff578 Mon Sep 17 00:00:00 2001 From: Phyks Date: Tue, 12 May 2015 00:23:50 +0200 Subject: [PATCH 4/9] Fix CMakeLists for include as a thirdparty in projects --- CMakeLists.txt | 6 +++--- CMakeModules/FindGTestSrc.cmake | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 380bdcd3c..b75775309 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules) +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules) PROJECT(RapidJSON CXX) @@ -17,7 +17,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON) option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON) option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON) -option(RAPIDJSON_BUILD_THIRDPARTY_GTEST +option(RAPIDJSON_BUILD_THIRDPARTY_GTEST "Use gtest installation in `thirdparty/gtest` by default if available" OFF) option(RAPIDJSON_HAS_STDSTRING "" OFF) @@ -45,7 +45,7 @@ ELSEIF(WIN32) ENDIF() SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in") -include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) if(RAPIDJSON_BUILD_DOC) add_subdirectory(doc) diff --git a/CMakeModules/FindGTestSrc.cmake b/CMakeModules/FindGTestSrc.cmake index b5abc19ae..f942a8daf 100644 --- a/CMakeModules/FindGTestSrc.cmake +++ b/CMakeModules/FindGTestSrc.cmake @@ -1,7 +1,7 @@ -SET(GTEST_SEARCH_PATH +SET(GTEST_SEARCH_PATH "${GTEST_SOURCE_DIR}" - "${CMAKE_SOURCE_DIR}/thirdparty/gtest") + "${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest") IF(UNIX) IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST) @@ -15,6 +15,7 @@ FIND_PATH(GTEST_SOURCE_DIR NAMES CMakeLists.txt src/gtest_main.cc PATHS ${GTEST_SEARCH_PATH}) + # Debian installs gtest include directory in /usr/include, thus need to look # for include directory separately from source directory. FIND_PATH(GTEST_INCLUDE_DIR From 2bd1171792e822a84e46ca484c7f7f2cbd523a62 Mon Sep 17 00:00:00 2001 From: Phyks Date: Tue, 12 May 2015 20:15:06 +0200 Subject: [PATCH 5/9] Forgot to update the CMakeLists.txt in doc folder --- doc/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 4e49c5f62..c1f165a37 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -3,9 +3,9 @@ find_package(Doxygen) IF(NOT DOXYGEN_FOUND) MESSAGE(STATUS "No Doxygen found. Documentation won't be built") ELSE() - file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/include/*) - file(GLOB MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/doc/*.md) - list(APPEND MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/readme.md) + file(GLOB SOURCES ${CMAKE_CURRENT_LIST_DIR}/../include/*) + file(GLOB MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../doc/*.md) + list(APPEND MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../readme.md) CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY) CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY) @@ -15,7 +15,7 @@ ELSE() COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile* - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../ ) add_custom_target(doc ALL DEPENDS html) From 6f830ec76bd12ec308b90573aa06348c779079ea Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 14 May 2015 12:03:21 +0800 Subject: [PATCH 6/9] Fix some numbers parsed incorrectly Fix #340 --- include/rapidjson/internal/strtod.h | 7 +++++- test/unittest/readertest.cpp | 35 ++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h index fa85286d4..ace65f677 100644 --- a/include/rapidjson/internal/strtod.h +++ b/include/rapidjson/internal/strtod.h @@ -191,8 +191,13 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + error) + if (precisionBits >= halfWay + error) { rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } *result = rounded.ToDouble(); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index bee19a8ea..910606378 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -193,7 +193,7 @@ static void TestParseDouble() { EXPECT_DOUBLE_EQ(x, h.actual_); \ } \ } - + TEST_DOUBLE(fullPrecision, "0.0", 0.0); TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289 TEST_DOUBLE(fullPrecision, "1.0", 1.0); @@ -327,15 +327,44 @@ static void TestParseDouble() { if (fullPrecision) { EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); if (d.Uint64Value() != a.Uint64Value()) - printf(" String: %sn Actual: %.17gnExpected: %.17gn", buffer, h.actual_, d.Value()); + printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); } else { - EXPECT_EQ(d.Sign(), a.Sign()); /* for 0.0 != -0.0 */ + EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 EXPECT_DOUBLE_EQ(d.Value(), h.actual_); } } } } + + // Issue #340 + TEST_DOUBLE(fullPrecision, "7.450580596923828e-9", 7.450580596923828e-9); + { + internal::Double d(1.0); + for (int i = 0; i < 324; i++) { + char buffer[32]; + *internal::dtoa(d.Value(), buffer) = '\0'; + + StringStream s(buffer); + ParseDoubleHandler h; + Reader reader; + ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); + EXPECT_EQ(1u, h.step_); + internal::Double a(h.actual_); + if (fullPrecision) { + EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); + if (d.Uint64Value() != a.Uint64Value()) + printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); + } + else { + EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 + EXPECT_DOUBLE_EQ(d.Value(), h.actual_); + } + + + d = d.Value() * 0.5; + } + } #undef TEST_DOUBLE } From fc8247c03662bfc1347794a4c6c71537feb5fc90 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 14 May 2015 14:48:10 +0800 Subject: [PATCH 7/9] v1.0.2 release --- CHANGELOG.md | 13 ++++++++++++- CMakeLists.txt | 2 +- appveyor.yml | 2 +- include/rapidjson/rapidjson.h | 2 +- readme.md | 2 +- readme.zh-cn.md | 2 +- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a405493..080694ccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,17 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [1.0.2] - 2015-05-14 + +### 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 (0691502573f1afd3341073dd24b12c3db20fbde4) + +### Changed +* CMakeLists for include as a thirdparty in projects (#334, #337) +* Change Document::ParseStream() to use stack allocator for Reader (ffbe38614732af8e0b3abdc8b50071f386a4a685) ## [1.0.1] - 2015-04-25 @@ -60,6 +70,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## 0.1 - 2011-11-18 -[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.1...HEAD +[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.2...HEAD +[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2 [1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index b75775309..68139ba3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ PROJECT(RapidJSON CXX) set(LIB_MAJOR_VERSION "1") set(LIB_MINOR_VERSION "0") -set(LIB_PATCH_VERSION "1") +set(LIB_PATCH_VERSION "2") set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}") # compile in release with debug info mode by default diff --git a/appveyor.yml b/appveyor.yml index add401782..7d586e83a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.0.1.{build} +version: 1.0.2.{build} configuration: - Debug diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index b06e82b01..f5d56308f 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -69,7 +69,7 @@ */ #define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 0 -#define RAPIDJSON_PATCH_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 2 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) diff --git a/readme.md b/readme.md index 98f81a731..19da38667 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ ![](doc/logo/rapidjson.png) -![](https://img.shields.io/badge/release-v1.0.1-blue.png) +![](https://img.shields.io/badge/release-v1.0.2-blue.png) ## A fast JSON parser/generator for C++ with both SAX/DOM style API diff --git a/readme.zh-cn.md b/readme.zh-cn.md index eb6c21d63..ec6bd9080 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -1,6 +1,6 @@ ![](doc/logo/rapidjson.png) -![](https://img.shields.io/badge/release-v1.0.1-blue.png) +![](https://img.shields.io/badge/release-v1.0.2-blue.png) ## 高效的C++ JSON解析/生成器,提供SAX及DOM风格API From 78337e9433b00b38cdf12bb8fa483008eaf92f48 Mon Sep 17 00:00:00 2001 From: miloyip Date: Tue, 12 May 2015 22:48:14 +0800 Subject: [PATCH 8/9] Add Value::XXXMember(...) overloads for std::string --- include/rapidjson/document.h | 50 ++++++++++++++++++++++++++++++++++++ test/unittest/valuetest.cpp | 22 ++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index aab489c05..ca809631e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -844,6 +844,12 @@ class GenericValue { template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } +#if RAPIDJSON_HAS_STDSTRING + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } +#endif + //! Const member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } @@ -867,6 +873,18 @@ class GenericValue { */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } +#if RAPIDJSON_HAS_STDSTRING + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } +#endif + //! Check whether a member exists in the object with GenericValue name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. @@ -923,6 +941,18 @@ class GenericValue { } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(StringRef(name)); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(StringRef(name)); } +#endif + //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. @@ -969,6 +999,22 @@ class GenericValue { return AddMember(name, v, allocator); } +#if RAPIDJSON_HAS_STDSTRING + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } +#endif + //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A string value as name of member. @@ -1087,6 +1133,10 @@ class GenericValue { return RemoveMember(n); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } +#endif + template bool RemoveMember(const GenericValue& name) { MemberIterator m = FindMember(name); diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 1922222a0..5e142e1e9 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -957,6 +957,19 @@ TEST(Value, Object) { EXPECT_EQ(2u, o.MemberCount()); } +#if RAPIDJSON_HAS_STDSTRING + { + // AddMember(StringRefType, const std::string&, Allocator) + Value o(kObjectType); + o.AddMember("b", std::string("Banana"), allocator); + EXPECT_STREQ("Banana", o["b"].GetString()); + + // RemoveMember(const std::string&) + o.RemoveMember(std::string("b")); + EXPECT_TRUE(o.ObjectEmpty()); + } +#endif + #if RAPIDJSON_HAS_CXX11_RVALUE_REFS // AddMember(GenericValue&&, ...) variants { @@ -986,6 +999,10 @@ TEST(Value, Object) { EXPECT_TRUE(y.HasMember("A")); EXPECT_TRUE(y.HasMember("B")); +#if RAPIDJSON_HAS_STDSTRING + EXPECT_TRUE(x.HasMember(std::string("A"))); +#endif + name.SetString("C\0D"); EXPECT_TRUE(x.HasMember(name)); EXPECT_TRUE(y.HasMember(name)); @@ -1009,6 +1026,11 @@ TEST(Value, Object) { EXPECT_STREQ("Banana", y["B"].GetString()); EXPECT_STREQ("CherryD", y[C0D].GetString()); +#if RAPIDJSON_HAS_STDSTRING + EXPECT_STREQ("Apple", x["A"].GetString()); + EXPECT_STREQ("Apple", y[std::string("A")].GetString()); +#endif + // member iterator Value::MemberIterator itr = x.MemberBegin(); EXPECT_TRUE(itr != x.MemberEnd()); From c5cbe97f39eb461707e2daec300941bd461c1d1e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 14 May 2015 14:59:26 +0800 Subject: [PATCH 9/9] Add one more commit about std::string from master --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 080694ccd..8ad9b3c35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.0.2] - 2015-05-14 +### 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)