Merge pull request #343 from miloyip/v1.0.2

V1.0.2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92a4054..8ad9b3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,20 @@
 
 ## [Unreleased]
 
+## [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)
+* 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 +73,7 @@
 
 ## 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 380bdcd..68139ba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,11 +1,11 @@
 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)
 
 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
@@ -17,7 +17,7 @@
 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 @@
 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 b5abc19..f942a8d 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 @@
     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
diff --git a/appveyor.yml b/appveyor.yml
index add4017..7d586e8 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/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 4e49c5f..c1f165a 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -3,9 +3,9 @@
 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 @@
         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)
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index b7042a5..f615ffd 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -143,11 +143,13 @@
 

     //! 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.

diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 7386773..ca80963 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -844,6 +844,12 @@
     template <typename SourceAllocator>

     const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }

 

+#if RAPIDJSON_HAS_STDSTRING

+    //! Get a value from an object associated with name (string object).

+    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }

+    const GenericValue& operator[](const std::basic_string<Ch>& 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 @@
     */

     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<Ch>& 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 @@
     }

     template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*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<Ch>& name) { return FindMember(StringRef(name)); }

+    ConstMemberIterator FindMember(const std::basic_string<Ch>& 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 @@
         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<Ch>& 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 @@
         return RemoveMember(n);

     }

 

+#if RAPIDJSON_HAS_STDSTRING

+    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }

+#endif

+

     template <typename SourceAllocator>

     bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {

         MemberIterator m = FindMember(name);

@@ -1741,7 +1791,7 @@
     template <unsigned parseFlags, typename SourceEncoding, typename InputStream>

     GenericDocument& ParseStream(InputStream& is) {

         ValueType::SetNull(); // Remove existing root if exist

-        GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());

+        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());

         ClearStackOnExit scope(*this);

         parseResult_ = reader.template Parse<parseFlags>(is, *this);

         if (parseResult_) {

diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h
index fa85286..ace65f6 100644
--- a/include/rapidjson/internal/strtod.h
+++ b/include/rapidjson/internal/strtod.h
@@ -191,8 +191,13 @@
     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/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h
index b06e82b..f5d5630 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 98f81a7..19da386 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 eb6c21d..ec6bd90 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
 
diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp
index 940b295..2ee6b10 100644
--- a/test/unittest/documenttest.cpp
+++ b/test/unittest/documenttest.cpp
@@ -241,7 +241,7 @@
     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));

diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp
index bee19a8..9106063 100644
--- a/test/unittest/readertest.cpp
+++ b/test/unittest/readertest.cpp
@@ -193,7 +193,7 @@
             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 @@
                 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<fullPrecision ? kParseFullPrecisionFlag : 0>(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

 }

 

diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp
index 1922222..5e142e1 100644
--- a/test/unittest/valuetest.cpp
+++ b/test/unittest/valuetest.cpp
@@ -957,6 +957,19 @@
         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 @@
     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 @@
     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());