Skip to content

Commit

Permalink
Merge pull request #343 from miloyip/v1.0.2
Browse files Browse the repository at this point in the history
V1.0.2
  • Loading branch information
miloyip committed May 14, 2015
2 parents 1034587 + c5cbe97 commit 3d5848a
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 22 deletions.
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [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

Expand Down Expand Up @@ -60,6 +73,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
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions CMakeModules/FindGTestSrc.cmake
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1.0.1.{build}
version: 1.0.2.{build}

configuration:
- Debug
Expand Down
8 changes: 4 additions & 4 deletions doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion include/rapidjson/allocators.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
52 changes: 51 additions & 1 deletion include/rapidjson/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,12 @@ class GenericValue {
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); }
Expand All @@ -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<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.
Expand Down Expand Up @@ -923,6 +941,18 @@ class GenericValue {
}
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.
Expand Down Expand Up @@ -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<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.
Expand Down Expand Up @@ -1087,6 +1133,10 @@ class GenericValue {
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);
Expand Down Expand Up @@ -1741,7 +1791,7 @@ class GenericDocument : public GenericValue<Encoding, Allocator> {
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_) {
Expand Down
7 changes: 6 additions & 1 deletion include/rapidjson/internal/strtod.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion include/rapidjson/rapidjson.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion readme.zh-cn.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion test/unittest/documenttest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
35 changes: 32 additions & 3 deletions test/unittest/readertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<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
}

Expand Down
22 changes: 22 additions & 0 deletions test/unittest/valuetest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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));
Expand All @@ -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());
Expand Down

0 comments on commit 3d5848a

Please sign in to comment.