Commit ca8e3d5d authored by Justin Scheiber's avatar Justin Scheiber

Merge branch 'master' of https://github.com/miloyip/rapidjson

parents 5be9b6e5 a326314a
...@@ -4,7 +4,20 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -4,7 +4,20 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [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. * 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 ## [1.0.1] - 2015-04-25
...@@ -60,6 +73,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -60,6 +73,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.1 - 2011-11-18 ## 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.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 [1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 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) PROJECT(RapidJSON CXX)
set(LIB_MAJOR_VERSION "1") set(LIB_MAJOR_VERSION "1")
set(LIB_MINOR_VERSION "0") 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}") set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}")
# compile in release with debug info mode by default # compile in release with debug info mode by default
...@@ -17,7 +17,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ...@@ -17,7 +17,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON)
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON) option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON)
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." 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) "Use gtest installation in `thirdparty/gtest` by default if available" OFF)
option(RAPIDJSON_HAS_STDSTRING "" OFF) option(RAPIDJSON_HAS_STDSTRING "" OFF)
...@@ -45,7 +45,7 @@ ELSEIF(WIN32) ...@@ -45,7 +45,7 @@ ELSEIF(WIN32)
ENDIF() ENDIF()
SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in") 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) if(RAPIDJSON_BUILD_DOC)
add_subdirectory(doc) add_subdirectory(doc)
......
SET(GTEST_SEARCH_PATH SET(GTEST_SEARCH_PATH
"${GTEST_SOURCE_DIR}" "${GTEST_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/thirdparty/gtest") "${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest")
IF(UNIX) IF(UNIX)
IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST) IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST)
...@@ -15,6 +15,7 @@ FIND_PATH(GTEST_SOURCE_DIR ...@@ -15,6 +15,7 @@ FIND_PATH(GTEST_SOURCE_DIR
NAMES CMakeLists.txt src/gtest_main.cc NAMES CMakeLists.txt src/gtest_main.cc
PATHS ${GTEST_SEARCH_PATH}) PATHS ${GTEST_SEARCH_PATH})
# Debian installs gtest include directory in /usr/include, thus need to look # Debian installs gtest include directory in /usr/include, thus need to look
# for include directory separately from source directory. # for include directory separately from source directory.
FIND_PATH(GTEST_INCLUDE_DIR FIND_PATH(GTEST_INCLUDE_DIR
......
version: 1.0.1.{build} version: 1.0.2.{build}
configuration: configuration:
- Debug - Debug
......
...@@ -3,9 +3,9 @@ find_package(Doxygen) ...@@ -3,9 +3,9 @@ find_package(Doxygen)
IF(NOT DOXYGEN_FOUND) IF(NOT DOXYGEN_FOUND)
MESSAGE(STATUS "No Doxygen found. Documentation won't be built") MESSAGE(STATUS "No Doxygen found. Documentation won't be built")
ELSE() ELSE()
file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/include/*) file(GLOB SOURCES ${CMAKE_CURRENT_LIST_DIR}/../include/*)
file(GLOB MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/doc/*.md) file(GLOB MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../doc/*.md)
list(APPEND MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/readme.md) list(APPEND MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../readme.md)
CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY) CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY) CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
...@@ -15,7 +15,7 @@ ELSE() ...@@ -15,7 +15,7 @@ ELSE()
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html
DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile* 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) add_custom_target(doc ALL DEPENDS html)
......
doc/diagram/architecture.png

10.7 KB | W: | H:

doc/diagram/architecture.png

16.2 KB | W: | H:

doc/diagram/architecture.png
doc/diagram/architecture.png
doc/diagram/architecture.png
doc/diagram/architecture.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/insituparsing.png

23.5 KB | W: | H:

doc/diagram/insituparsing.png

36.4 KB | W: | H:

doc/diagram/insituparsing.png
doc/diagram/insituparsing.png
doc/diagram/insituparsing.png
doc/diagram/insituparsing.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/move1.png

7.99 KB | W: | H:

doc/diagram/move1.png

15.7 KB | W: | H:

doc/diagram/move1.png
doc/diagram/move1.png
doc/diagram/move1.png
doc/diagram/move1.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/move2.png

26.1 KB | W: | H:

doc/diagram/move2.png

40.5 KB | W: | H:

doc/diagram/move2.png
doc/diagram/move2.png
doc/diagram/move2.png
doc/diagram/move2.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/move3.png

22.1 KB | W: | H:

doc/diagram/move3.png

35.5 KB | W: | H:

doc/diagram/move3.png
doc/diagram/move3.png
doc/diagram/move3.png
doc/diagram/move3.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/normalparsing.png

22.1 KB | W: | H:

doc/diagram/normalparsing.png

32.1 KB | W: | H:

doc/diagram/normalparsing.png
doc/diagram/normalparsing.png
doc/diagram/normalparsing.png
doc/diagram/normalparsing.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/simpledom.png

23.5 KB | W: | H:

doc/diagram/simpledom.png

42.6 KB | W: | H:

doc/diagram/simpledom.png
doc/diagram/simpledom.png
doc/diagram/simpledom.png
doc/diagram/simpledom.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/tutorial.png

32.4 KB | W: | H:

doc/diagram/tutorial.png

43.6 KB | W: | H:

doc/diagram/tutorial.png
doc/diagram/tutorial.png
doc/diagram/tutorial.png
doc/diagram/tutorial.png
  • 2-up
  • Swipe
  • Onion skin
doc/diagram/utilityclass.png

60.9 KB | W: | H:

doc/diagram/utilityclass.png

97.6 KB | W: | H:

doc/diagram/utilityclass.png
doc/diagram/utilityclass.png
doc/diagram/utilityclass.png
doc/diagram/utilityclass.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -16,6 +16,15 @@ $mathjax ...@@ -16,6 +16,15 @@ $mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet $extrastylesheet
</head> </head>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63929386-1', 'auto');
ga('send', 'pageview');
</script>
<body> <body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! --> <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div> <div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
......
...@@ -143,11 +143,13 @@ public: ...@@ -143,11 +143,13 @@ public:
//! Deallocates all memory chunks, excluding the user-supplied buffer. //! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() { void Clear() {
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next; ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_); baseAllocator_->Free(chunkHead_);
chunkHead_ = next; chunkHead_ = next;
} }
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
} }
//! Computes the total capacity of allocated memory chunks. //! Computes the total capacity of allocated memory chunks.
...@@ -179,7 +181,7 @@ public: ...@@ -179,7 +181,7 @@ public:
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size; void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size; chunkHead_->size += size;
return buffer; return buffer;
} }
...@@ -197,7 +199,7 @@ public: ...@@ -197,7 +199,7 @@ public:
return originalPtr; return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space // Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize); size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment); increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) { if (chunkHead_->size + increment <= chunkHead_->capacity) {
...@@ -229,7 +231,7 @@ private: ...@@ -229,7 +231,7 @@ private:
void AddChunk(size_t capacity) { void AddChunk(size_t capacity) {
if (!baseAllocator_) if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
chunk->capacity = capacity; chunk->capacity = capacity;
chunk->size = 0; chunk->size = 0;
chunk->next = chunkHead_; chunk->next = chunkHead_;
......
...@@ -844,6 +844,12 @@ public: ...@@ -844,6 +844,12 @@ public:
template <typename SourceAllocator> template <typename SourceAllocator>
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; } 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 //! Const member iterator
/*! \pre IsObject() == true */ /*! \pre IsObject() == true */
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
...@@ -867,6 +873,18 @@ public: ...@@ -867,6 +873,18 @@ public:
*/ */
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } 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. //! 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. This version is faster because it does not need a StrLen(). It can also handle string with null character.
...@@ -923,6 +941,18 @@ public: ...@@ -923,6 +941,18 @@ public:
} }
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); } 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. //! Add a member (name-value pair) to the object.
/*! \param name A string value as name of member. /*! \param name A string value as name of member.
\param value Value of any type. \param value Value of any type.
...@@ -969,6 +999,22 @@ public: ...@@ -969,6 +999,22 @@ public:
return AddMember(name, v, allocator); 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. //! 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 /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param name A string value as name of member. \param name A string value as name of member.
...@@ -1087,6 +1133,10 @@ public: ...@@ -1087,6 +1133,10 @@ public:
return RemoveMember(n); return RemoveMember(n);
} }
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator> template <typename SourceAllocator>
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) { bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name); MemberIterator m = FindMember(name);
...@@ -1163,6 +1213,31 @@ public: ...@@ -1163,6 +1213,31 @@ public:
return pos; return pos;
} }
//! Erase a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note Linear time complexity.
*/
bool EraseMember(const Ch* name) {
GenericValue n(StringRef(name));
return EraseMember(n);
}
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator>
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
if (m != MemberEnd()) {
EraseMember(m);
return true;
}
else
return false;
}
//@} //@}
//!@name Array //!@name Array
...@@ -1741,7 +1816,7 @@ public: ...@@ -1741,7 +1816,7 @@ public:
template <unsigned parseFlags, typename SourceEncoding, typename InputStream> template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { GenericDocument& ParseStream(InputStream& is) {
ValueType::SetNull(); // Remove existing root if exist ValueType::SetNull(); // Remove existing root if exist
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator()); GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this); parseResult_ = reader.template Parse<parseFlags>(is, *this);
if (parseResult_) { if (parseResult_) {
......
...@@ -191,8 +191,13 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit ...@@ -191,8 +191,13 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (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++; rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble(); *result = rounded.ToDouble();
......
This diff is collapsed.
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
*/ */
#define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MAJOR_VERSION 1
#define RAPIDJSON_MINOR_VERSION 0 #define RAPIDJSON_MINOR_VERSION 0
#define RAPIDJSON_PATCH_VERSION 1 #define RAPIDJSON_PATCH_VERSION 2
#define RAPIDJSON_VERSION_STRING \ #define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
...@@ -223,7 +223,7 @@ ...@@ -223,7 +223,7 @@
//! Whether using 64-bit architecture //! Whether using 64-bit architecture
#ifndef RAPIDJSON_64BIT #ifndef RAPIDJSON_64BIT
#if defined(__LP64__) || defined(_WIN64) #if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
#define RAPIDJSON_64BIT 1 #define RAPIDJSON_64BIT 1
#else #else
#define RAPIDJSON_64BIT 0 #define RAPIDJSON_64BIT 0
......
...@@ -271,7 +271,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) { ...@@ -271,7 +271,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
// The rest of string using SIMD // The rest of string using SIMD
static const char whitespace[16] = " \n\r\t"; static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]); const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128((const __m128i *)p);
...@@ -967,13 +967,13 @@ private: ...@@ -967,13 +967,13 @@ private:
else { else {
if (use64bit) { if (use64bit) {
if (minus) if (minus)
cont = handler.Int64(-(int64_t)i64); cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else else
cont = handler.Uint64(i64); cont = handler.Uint64(i64);
} }
else { else {
if (minus) if (minus)
cont = handler.Int(-(int)i); cont = handler.Int(static_cast<int32_t>(~i + 1));
else else
cont = handler.Uint(i); cont = handler.Uint(i);
} }
...@@ -1387,13 +1387,13 @@ private: ...@@ -1387,13 +1387,13 @@ private:
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
case IterativeParsingObjectInitialState: case IterativeParsingObjectInitialState:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
} }
} }
......
![](doc/logo/rapidjson.png) ![](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 ## A fast JSON parser/generator for C++ with both SAX/DOM style API
...@@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights ...@@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) * [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
* RapidJSON Documentation * RapidJSON Documentation
* [English](http://miloyip.github.io/rapidjson/) * [English](http://rapidjson.org/)
* [简体中文](http://miloyip.github.io/rapidjson/zh-cn/) * [简体中文](http://rapidjson.org/zh-cn/)
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
## Build status ## Build status
......
![](doc/logo/rapidjson.png) ![](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 ## 高效的C++ JSON解析/生成器,提供SAX及DOM风格API
...@@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights ...@@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) * [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
* RapidJSON 文档 * RapidJSON 文档
* [English](http://miloyip.github.io/rapidjson/) * [English](http://rapidjson.org/)
* [简体中文](http://miloyip.github.io/rapidjson/zh-cn/) * [简体中文](http://rapidjson.org/zh-cn/)
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/)可下载PDF/EPUB/MOBI,但不含API参考手册。 * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/)可下载PDF/EPUB/MOBI,但不含API参考手册。
## Build 状态 ## Build 状态
......
...@@ -298,11 +298,28 @@ TEST_F(RapidJson, internal_Pow10) { ...@@ -298,11 +298,28 @@ TEST_F(RapidJson, internal_Pow10) {
EXPECT_GT(sum, 0.0); EXPECT_GT(sum, 0.0);
} }
TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) { TEST_F(RapidJson, SkipWhitespace_Basic) {
for (size_t i = 0; i < kTrialCount; i++) { for (size_t i = 0; i < kTrialCount; i++) {
Document doc; rapidjson::StringStream s(whitespace_);
ASSERT_TRUE(doc.Parse(whitespace_).IsArray()); while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
} s.Take();
ASSERT_EQ('[', s.Peek());
}
}
TEST_F(RapidJson, SIMD_SUFFIX(SkipWhitespace)) {
for (size_t i = 0; i < kTrialCount; i++) {
rapidjson::StringStream s(whitespace_);
rapidjson::SkipWhitespace(s);
ASSERT_EQ('[', s.Peek());
}
}
TEST_F(RapidJson, SkipWhitespace_strspn) {
for (size_t i = 0; i < kTrialCount; i++) {
const char* s = whitespace_ + std::strspn(whitespace_, " \t\r\n");
ASSERT_EQ('[', *s);
}
} }
TEST_F(RapidJson, UTF8_Validate) { TEST_F(RapidJson, UTF8_Validate) {
......
...@@ -21,7 +21,7 @@ set(UNITTEST_SOURCES ...@@ -21,7 +21,7 @@ set(UNITTEST_SOURCES
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
endif() endif()
......
...@@ -241,7 +241,7 @@ TEST(Document, UserBuffer) { ...@@ -241,7 +241,7 @@ TEST(Document, UserBuffer) {
char parseBuffer[1024]; char parseBuffer[1024];
MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer)); MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer)); 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] } "); 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_FALSE(doc.HasParseError());
EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer)); EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
......
...@@ -39,12 +39,22 @@ TEST(Pointer, Parse) { ...@@ -39,12 +39,22 @@ TEST(Pointer, Parse) {
EXPECT_EQ(0u, p.GetTokenCount()); EXPECT_EQ(0u, p.GetTokenCount());
} }
{
Pointer p("/");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
{ {
Pointer p("/foo"); Pointer p("/foo");
EXPECT_TRUE(p.IsValid()); EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
...@@ -54,6 +64,7 @@ TEST(Pointer, Parse) { ...@@ -54,6 +64,7 @@ TEST(Pointer, Parse) {
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
} }
#endif #endif
...@@ -63,6 +74,7 @@ TEST(Pointer, Parse) { ...@@ -63,6 +74,7 @@ TEST(Pointer, Parse) {
EXPECT_EQ(2u, p.GetTokenCount()); EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
EXPECT_EQ(1u, p.GetTokens()[1].length); EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("0", p.GetTokens()[1].name); EXPECT_STREQ("0", p.GetTokens()[1].name);
EXPECT_EQ(0u, p.GetTokens()[1].index); EXPECT_EQ(0u, p.GetTokens()[1].index);
...@@ -481,6 +493,14 @@ TEST(Pointer, Assignment) { ...@@ -481,6 +493,14 @@ TEST(Pointer, Assignment) {
EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index); EXPECT_EQ(0u, q.GetTokens()[1].index);
q = q;
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
} }
// Static tokens // Static tokens
...@@ -498,6 +518,36 @@ TEST(Pointer, Assignment) { ...@@ -498,6 +518,36 @@ TEST(Pointer, Assignment) {
} }
} }
TEST(Pointer, Append) {
{
Pointer p;
Pointer q = p.Append("foo");
EXPECT_TRUE(Pointer("/foo") == q);
q = q.Append(1234);
EXPECT_TRUE(Pointer("/foo/1234") == q);
q = q.Append("");
EXPECT_TRUE(Pointer("/foo/1234/") == q);
}
{
Pointer p;
Pointer q = p.Append(Value("foo").Move());
EXPECT_TRUE(Pointer("/foo") == q);
q = q.Append(Value(1234).Move());
EXPECT_TRUE(Pointer("/foo/1234") == q);
q = q.Append(Value(kStringType).Move());
EXPECT_TRUE(Pointer("/foo/1234/") == q);
}
#if RAPIDJSON_HAS_STDSTRING
{
Pointer p;
Pointer q = p.Append(std::string("foo"));
EXPECT_TRUE(Pointer("/foo") == q);
}
#endif
}
TEST(Pointer, Equality) { TEST(Pointer, Equality) {
EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0")); EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1")); EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
...@@ -823,7 +873,13 @@ TEST(Pointer, Erase) { ...@@ -823,7 +873,13 @@ TEST(Pointer, Erase) {
d.Parse(kJson); d.Parse(kJson);
EXPECT_FALSE(Pointer("").Erase(d)); EXPECT_FALSE(Pointer("").Erase(d));
EXPECT_FALSE(Pointer("/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d)); EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/0/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/0/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/2/nonexist").Erase(d));
EXPECT_TRUE(Pointer("/foo/0").Erase(d)); EXPECT_TRUE(Pointer("/foo/0").Erase(d));
EXPECT_EQ(1u, d["foo"].Size()); EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString()); EXPECT_STREQ("baz", d["foo"][0].GetString());
...@@ -831,6 +887,24 @@ TEST(Pointer, Erase) { ...@@ -831,6 +887,24 @@ TEST(Pointer, Erase) {
EXPECT_TRUE(d["foo"].Empty()); EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(Pointer("/foo").Erase(d)); EXPECT_TRUE(Pointer("/foo").Erase(d));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0); EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
Pointer("/a/0/b/0").Create(d);
EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0/b/0").Erase(d));
EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) == 0);
EXPECT_TRUE(Pointer("/a/0/b").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0/b").Erase(d));
EXPECT_TRUE(Pointer("/a/0/b").Get(d) == 0);
EXPECT_TRUE(Pointer("/a/0").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0").Erase(d));
EXPECT_TRUE(Pointer("/a/0").Get(d) == 0);
EXPECT_TRUE(Pointer("/a").Get(d) != 0);
EXPECT_TRUE(Pointer("/a").Erase(d));
EXPECT_TRUE(Pointer("/a").Get(d) == 0);
} }
TEST(Pointer, CreateValueByPointer) { TEST(Pointer, CreateValueByPointer) {
......
...@@ -193,7 +193,7 @@ static void TestParseDouble() { ...@@ -193,7 +193,7 @@ static void TestParseDouble() {
EXPECT_DOUBLE_EQ(x, h.actual_); \ EXPECT_DOUBLE_EQ(x, h.actual_); \
} \ } \
} }
TEST_DOUBLE(fullPrecision, "0.0", 0.0); TEST_DOUBLE(fullPrecision, "0.0", 0.0);
TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289 TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289
TEST_DOUBLE(fullPrecision, "1.0", 1.0); TEST_DOUBLE(fullPrecision, "1.0", 1.0);
...@@ -327,15 +327,44 @@ static void TestParseDouble() { ...@@ -327,15 +327,44 @@ static void TestParseDouble() {
if (fullPrecision) { if (fullPrecision) {
EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); EXPECT_EQ(d.Uint64Value(), a.Uint64Value());
if (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 { 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_); 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 #undef TEST_DOUBLE
} }
......
...@@ -957,6 +957,19 @@ TEST(Value, Object) { ...@@ -957,6 +957,19 @@ TEST(Value, Object) {
EXPECT_EQ(2u, o.MemberCount()); 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 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
// AddMember(GenericValue&&, ...) variants // AddMember(GenericValue&&, ...) variants
{ {
...@@ -986,6 +999,10 @@ TEST(Value, Object) { ...@@ -986,6 +999,10 @@ TEST(Value, Object) {
EXPECT_TRUE(y.HasMember("A")); EXPECT_TRUE(y.HasMember("A"));
EXPECT_TRUE(y.HasMember("B")); EXPECT_TRUE(y.HasMember("B"));
#if RAPIDJSON_HAS_STDSTRING
EXPECT_TRUE(x.HasMember(std::string("A")));
#endif
name.SetString("C\0D"); name.SetString("C\0D");
EXPECT_TRUE(x.HasMember(name)); EXPECT_TRUE(x.HasMember(name));
EXPECT_TRUE(y.HasMember(name)); EXPECT_TRUE(y.HasMember(name));
...@@ -1009,6 +1026,11 @@ TEST(Value, Object) { ...@@ -1009,6 +1026,11 @@ TEST(Value, Object) {
EXPECT_STREQ("Banana", y["B"].GetString()); EXPECT_STREQ("Banana", y["B"].GetString());
EXPECT_STREQ("CherryD", y[C0D].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 // member iterator
Value::MemberIterator itr = x.MemberBegin(); Value::MemberIterator itr = x.MemberBegin();
EXPECT_TRUE(itr != x.MemberEnd()); EXPECT_TRUE(itr != x.MemberEnd());
...@@ -1160,6 +1182,24 @@ TEST(Value, Object) { ...@@ -1160,6 +1182,24 @@ TEST(Value, Object) {
EXPECT_TRUE(z.IsObject()); EXPECT_TRUE(z.IsObject());
} }
TEST(Value, EraseMember_String) {
Value::AllocatorType allocator;
Value x(kObjectType);
x.AddMember("A", "Apple", allocator);
x.AddMember("B", "Banana", allocator);
EXPECT_TRUE(x.EraseMember("B"));
EXPECT_FALSE(x.HasMember("B"));
EXPECT_FALSE(x.EraseMember("nonexist"));
GenericValue<UTF8<>, CrtAllocator> othername("A");
EXPECT_TRUE(x.EraseMember(othername));
EXPECT_FALSE(x.HasMember("A"));
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
}
TEST(Value, BigNestedArray) { TEST(Value, BigNestedArray) {
MemoryPoolAllocator<> allocator; MemoryPoolAllocator<> allocator;
Value x(kArrayType); Value x(kArrayType);
......
...@@ -78,6 +78,7 @@ gh_pages_prepare() ...@@ -78,6 +78,7 @@ gh_pages_prepare()
gh_pages_commit() { gh_pages_commit() {
cd "${TRAVIS_BUILD_DIR}/build/doc/html"; cd "${TRAVIS_BUILD_DIR}/build/doc/html";
echo "rapidjson.org" > CNAME
git add --all; git add --all;
git diff-index --quiet HEAD || git commit -m "Automatic doxygen build"; git diff-index --quiet HEAD || git commit -m "Automatic doxygen build";
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment