Merge branch 'master' into json-pointer

Conflicts:
	test/unittest/CMakeLists.txt
This commit is contained in:
miloyip 2015-05-03 20:27:21 +08:00
commit 7fc716006f
62 changed files with 1551 additions and 813 deletions

View File

@ -18,8 +18,10 @@ env:
before_install: before_install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq cmake doxygen valgrind - sudo apt-get install -qq cmake valgrind
- sudo apt-get --no-install-recommends install doxygen # Don't install LaTeX stuffs
- if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi - if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi
- if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi
install: true install: true
@ -34,7 +36,9 @@ before_script:
-DRAPIDJSON_HAS_STDSTRING=ON -DRAPIDJSON_HAS_STDSTRING=ON
-DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_VERBOSE_MAKEFILE=ON
-DCMAKE_BUILD_TYPE=$CONF -DCMAKE_BUILD_TYPE=$CONF
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" ..) -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
..)
script: script:
- cd build - cd build
@ -42,3 +46,6 @@ script:
- make examples - make examples
- ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"` - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"`
- make travis_doc - make travis_doc
after_success:
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h

65
CHANGELOG.md Normal file
View File

@ -0,0 +1,65 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
* Include rapidjson.h for all internal/error headers.
## [1.0.1] - 2015-04-25
### Added
* Changelog following [Keep a CHANGELOG](https://github.com/olivierlacan/keep-a-changelog) suggestions.
### Fixed
* Parsing of some numbers (e.g. "1e-00011111111111") causing assertion (#314).
* Visual C++ 32-bit compilation error in `diyfp.h` (#317).
## [1.0.0] - 2015-04-22
### Added
* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage.
* Version macros (#311)
### Fixed
* A bug in trimming long number sequence (4824f12efbf01af72b8cb6fc96fae7b097b73015).
* Double quote in unicode escape (#288).
* Negative zero roundtrip (double only) (#289).
* Standardize behavior of `memcpy()` and `malloc()` (0c5c1538dcfc7f160e5a4aa208ddf092c787be5a, #305, 0e8bbe5e3ef375e7f052f556878be0bd79e9062d).
### Removed
* Remove an invalid `Document::ParseInsitu()` API (e7f1c6dd08b522cfcf9aed58a333bd9a0c0ccbeb).
## 1.0-beta - 2015-04-8
### Added
* RFC 7159 (#101)
* Optional Iterative Parser (#76)
* Deep-copy values (#20)
* Error code and message (#27)
* ASCII Encoding (#70)
* `kParseStopWhenDoneFlag` (#83)
* `kParseFullPrecisionFlag` (881c91d696f06b7f302af6d04ec14dd08db66ceb)
* Add `Key()` to handler concept (#134)
* C++11 compatibility and support (#128)
* Optimized number-to-string and vice versa conversions (#137, #80)
* Short-String Optimization (#131)
* Local stream optimization by traits (#32)
* Travis & Appveyor Continuous Integration, with Valgrind verification (#24, #242)
* Redo all documentation (English, Simplified Chinese)
### Changed
* Copyright ownership transfered to THL A29 Limited (a Tencent company).
* Migrating from Premake to CMAKE (#192)
* Resolve all warning reports
### Removed
* Remove other JSON libraries for performance comparison (#180)
## 0.11 - 2012-11-16
## 0.1 - 2011-11-18
[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.1...HEAD
[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

View File

@ -3,9 +3,9 @@ SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules)
PROJECT(RapidJSON CXX) PROJECT(RapidJSON CXX)
set(LIB_MAJOR_VERSION "0") set(LIB_MAJOR_VERSION "1")
set(LIB_MINOR_VERSION "12") set(LIB_MINOR_VERSION "0")
set(LIB_PATCH_VERSION "0") set(LIB_PATCH_VERSION "1")
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,6 +17,8 @@ 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
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
option(RAPIDJSON_HAS_STDSTRING "" OFF) option(RAPIDJSON_HAS_STDSTRING "" OFF)
if(RAPIDJSON_HAS_STDSTRING) if(RAPIDJSON_HAS_STDSTRING)

View File

@ -1,9 +1,14 @@
SET(GTEST_SEARCH_PATH SET(GTEST_SEARCH_PATH
"${GTEST_SOURCE_DIR}" "${GTEST_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/thirdparty/gtest") "${CMAKE_SOURCE_DIR}/thirdparty/gtest")
IF(UNIX) IF(UNIX)
LIST(INSERT GTEST_SEARCH_PATH 1 "/usr/src/gtest") IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST)
LIST(APPEND GTEST_SEARCH_PATH "/usr/src/gtest")
ELSE()
LIST(INSERT GTEST_SEARCH_PATH 1 "/usr/src/gtest")
ENDIF()
ENDIF() ENDIF()
FIND_PATH(GTEST_SOURCE_DIR FIND_PATH(GTEST_SOURCE_DIR
@ -15,8 +20,10 @@ FIND_PATH(GTEST_SOURCE_DIR
FIND_PATH(GTEST_INCLUDE_DIR FIND_PATH(GTEST_INCLUDE_DIR
NAMES gtest/gtest.h NAMES gtest/gtest.h
PATH_SUFFIXES include PATH_SUFFIXES include
HINTS ${GTEST_SOURCE_DIR}
PATHS ${GTEST_SEARCH_PATH}) PATHS ${GTEST_SEARCH_PATH})
INCLUDE(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GTestSrc DEFAULT_MSG find_package_handle_standard_args(GTestSrc DEFAULT_MSG
GTEST_SOURCE_DIR GTEST_SOURCE_DIR
GTEST_INCLUDE_DIR) GTEST_INCLUDE_DIR)

View File

@ -1,4 +1,4 @@
version: 0.12.{build} version: 1.0.1.{build}
configuration: configuration:
- Debug - Debug

View File

@ -84,29 +84,25 @@ template <typename InputStream>
GenericDocument& GenericDocument::ParseStream(InputStream& is); GenericDocument& GenericDocument::ParseStream(InputStream& is);
// (4) In situ parsing // (4) In situ parsing
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (5) In situ parsing, using same Encoding of Document
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& GenericDocument::ParseInsitu(Ch* str); GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (6) In situ parsing, using default parse flags // (5) In situ parsing, using default parse flags
GenericDocument& GenericDocument::ParseInsitu(Ch* str); GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (7) Normal parsing of a string // (6) Normal parsing of a string
template <unsigned parseFlags, typename SourceEncoding> template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
// (8) Normal parsing of a string, using same Encoding of Document // (7) Normal parsing of a string, using same Encoding of Document
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
// (9) Normal parsing of a string, using default parse flags // (8) Normal parsing of a string, using default parse flags
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
~~~~~~~~~~ ~~~~~~~~~~
The examples of [tutorial](doc/tutorial.md) uses (9) for normal parsing of string. The examples of [stream](doc/stream.md) uses the first three. *In situ* parsing will be described soon. The examples of [tutorial](doc/tutorial.md) uses (8) for normal parsing of string. The examples of [stream](doc/stream.md) uses the first three. *In situ* parsing will be described soon.
The `parseFlags` are combination of the following bit-flags: The `parseFlags` are combination of the following bit-flags:

View File

@ -84,29 +84,25 @@ template <typename InputStream>
GenericDocument& GenericDocument::ParseStream(InputStream& is); GenericDocument& GenericDocument::ParseStream(InputStream& is);
// (4) 原位解析 // (4) 原位解析
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (5) 原位解析使用Document的编码
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& GenericDocument::ParseInsitu(Ch* str); GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (6) 原位解析,使用缺省标志 // (5) 原位解析,使用缺省标志
GenericDocument& GenericDocument::ParseInsitu(Ch* str); GenericDocument& GenericDocument::ParseInsitu(Ch* str);
// (7) 正常解析一个字符串 // (6) 正常解析一个字符串
template <unsigned parseFlags, typename SourceEncoding> template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
// (8) 正常解析一个字符串使用Document的编码 // (7) 正常解析一个字符串使用Document的编码
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
// (9) 正常解析一个字符串,使用缺省标志 // (8) 正常解析一个字符串,使用缺省标志
GenericDocument& GenericDocument::Parse(const Ch* str); GenericDocument& GenericDocument::Parse(const Ch* str);
~~~~~~~~~~ ~~~~~~~~~~
[教程](tutorial.md)中的例使用(9)去正常解析字符串。而[](stream.md)的例子使用前3个函数。我们将稍后介绍原位*In situ* 解析。 [教程](tutorial.md)中的例使用(8)去正常解析字符串。而[](stream.md)的例子使用前3个函数。我们将稍后介绍原位*In situ* 解析。
`parseFlags`是以下位标置的组合: `parseFlags`是以下位标置的组合:

View File

@ -28,7 +28,7 @@
6. How to install RapidJSON? 6. How to install RapidJSON?
Check [Installation section](http://miloyip.github.io/rapidjson/). Check [Installation section](https://miloyip.github.io/rapidjson/).
7. Can RapidJSON run on my platform? 7. Can RapidJSON run on my platform?
@ -198,7 +198,7 @@
3. What is SIMD? How it is applied in RapidJSON? 3. What is SIMD? How it is applied in RapidJSON?
[SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.1 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
4. Does it consume a lot of memory? 4. Does it consume a lot of memory?

View File

@ -198,7 +198,7 @@
3. 什是是SIMD它如何用于RapidJSON 3. 什是是SIMD它如何用于RapidJSON
[SIMD](http://en.wikipedia.org/wiki/SIMD)指令可以在现代CPU中执行并行运算。RapidJSON支持了Intel的SSE2/SSE4.1去加速跳过空白字符。在解析含缩进的JSON时这能提升性能。 [SIMD](http://en.wikipedia.org/wiki/SIMD)指令可以在现代CPU中执行并行运算。RapidJSON支持了Intel的SSE2/SSE4.2去加速跳过空白字符。在解析含缩进的JSON时这能提升性能。只要定义名为`RAPIDJSON_SSE2``RAPIDJSON_SSE42`的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。
4. 它会消耗许多内存么? 4. 它会消耗许多内存么?

View File

@ -15,7 +15,7 @@
* High performance * High performance
* Use template and inline functions to reduce function call overheads. * Use template and inline functions to reduce function call overheads.
* Internal optimized Grisu2 and floating point parsing implementations. * Internal optimized Grisu2 and floating point parsing implementations.
* Optional SSE2/SSE4.1 support. * Optional SSE2/SSE4.2 support.
## Standard compliance ## Standard compliance

View File

@ -15,7 +15,7 @@
* 高性能 * 高性能
* 使用模版及内联函数去降低函数调用开销。 * 使用模版及内联函数去降低函数调用开销。
* 内部经优化的Grisu2及浮点数解析实现。 * 内部经优化的Grisu2及浮点数解析实现。
* 可选的SSE2/SSE4.1支持。 * 可选的SSE2/SSE4.2支持。
## 符合标准 ## 符合标准

View File

@ -183,7 +183,21 @@ void SkipWhitespace(InputStream& s) {
However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot. However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot.
To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.1 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing. To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
~~~cpp
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
#endif
~~~
Note that, these are compile-time settings. Running the executable on a machine without such instruction set support will make it crash.
## Local Stream Copy {#LocalStreamCopy} ## Local Stream Copy {#LocalStreamCopy}

View File

@ -18,10 +18,10 @@
(document.getElementsByClassName('contents')[0]).appendChild(dt); (document.getElementsByClassName('contents')[0]).appendChild(dt);
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})(); })();
</script> </script>
</body> </body>
</html> </html>

View File

@ -192,7 +192,7 @@ Checking | Obtaining
`bool IsNumber()` | N/A `bool IsNumber()` | N/A
`bool IsUint()` | `unsigned GetUint()` `bool IsUint()` | `unsigned GetUint()`
`bool IsInt()` | `int GetInt()` `bool IsInt()` | `int GetInt()`
`bool IsUint64()` | `uint64_t GetUint()` `bool IsUint64()` | `uint64_t GetUint64()`
`bool IsInt64()` | `int64_t GetInt64()` `bool IsInt64()` | `int64_t GetInt64()`
`bool IsDouble()` | `double GetDouble()` `bool IsDouble()` | `double GetDouble()`

View File

@ -192,7 +192,7 @@ JSON只提供一种数值类型──Number。数字可以是整数或实数。R
`bool IsNumber()` | 不适用 `bool IsNumber()` | 不适用
`bool IsUint()` | `unsigned GetUint()` `bool IsUint()` | `unsigned GetUint()`
`bool IsInt()` | `int GetInt()` `bool IsInt()` | `int GetInt()`
`bool IsUint64()` | `uint64_t GetUint()` `bool IsUint64()` | `uint64_t GetUint64()`
`bool IsInt64()` | `int64_t GetInt64()` `bool IsInt64()` | `int64_t GetInt64()`
`bool IsDouble()` | `double GetDouble()` `bool IsDouble()` | `double GetDouble()`

View File

@ -2,7 +2,6 @@
// This example shows writing JSON string with writer directly. // This example shows writing JSON string with writer directly.
#include "rapidjson/prettywriter.h" // for stringify JSON #include "rapidjson/prettywriter.h" // for stringify JSON
#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <vector> #include <vector>
@ -144,13 +143,15 @@ int main(int, char*[]) {
employees.push_back(Employee("Percy TSE", 30, false)); employees.push_back(Employee("Percy TSE", 30, false));
FileStream s(stdout); StringBuffer sb;
PrettyWriter<FileStream> writer(s); // Can also use Writer for condensed formatting PrettyWriter<StringBuffer> writer(sb);
writer.StartArray(); writer.StartArray();
for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr) for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
employeeItr->Serialize(writer); employeeItr->Serialize(writer);
writer.EndArray(); writer.EndArray();
puts(sb.GetString());
return 0; return 0;
} }

View File

@ -3,7 +3,6 @@
#include "rapidjson/document.h" // rapidjson's DOM-style API #include "rapidjson/document.h" // rapidjson's DOM-style API
#include "rapidjson/prettywriter.h" // for stringify JSON #include "rapidjson/prettywriter.h" // for stringify JSON
#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output
#include <cstdio> #include <cstdio>
using namespace rapidjson; using namespace rapidjson;
@ -143,9 +142,10 @@ int main(int, char*[]) {
// 4. Stringify JSON // 4. Stringify JSON
printf("\nModified JSON with reformatting:\n"); printf("\nModified JSON with reformatting:\n");
FileStream f(stdout); StringBuffer sb;
PrettyWriter<FileStream> writer(f); PrettyWriter<StringBuffer> writer(sb);
document.Accept(writer); // Accept() traverses the DOM and generates Handler events. document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
puts(sb.GetString());
return 0; return 0;
} }

View File

@ -62,7 +62,12 @@ concept Allocator {
class CrtAllocator { class CrtAllocator {
public: public:
static const bool kNeedFree = true; static const bool kNeedFree = true;
void* Malloc(size_t size) { return std::malloc(size); } void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); }
static void Free(void *ptr) { std::free(ptr); } static void Free(void *ptr) { std::free(ptr); }
}; };
@ -160,6 +165,9 @@ public:
//! Allocates a memory block. (concept Allocator) //! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) { void* Malloc(size_t size) {
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size); size = RAPIDJSON_ALIGN(size);
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);
@ -191,7 +199,9 @@ public:
// Realloc process: allocate and copy memory, do not free original buffer. // Realloc process: allocate and copy memory, do not free original buffer.
void* newBuffer = Malloc(newSize); void* newBuffer = Malloc(newSize);
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
return std::memcpy(newBuffer, originalPtr, originalSize); if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
} }
//! Frees a memory block (concept Allocator) //! Frees a memory block (concept Allocator)

View File

@ -701,8 +701,11 @@ public:
return StringEqual(rhs); return StringEqual(rhs);
case kNumberType: case kNumberType:
if (IsDouble() || rhs.IsDouble()) if (IsDouble() || rhs.IsDouble()) {
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. double a = GetDouble(); // May convert from integer to double.
double b = rhs.GetDouble(); // Ditto
return a >= b && a <= b; // Prevent -Wfloat-equal
}
else else
return data_.n.u64 == rhs.data_.n.u64; return data_.n.u64 == rhs.data_.n.u64;
@ -1457,17 +1460,14 @@ public:
case kStringType: case kStringType:
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
case kNumberType: default:
RAPIDJSON_ASSERT(GetType() == kNumberType);
if (IsInt()) return handler.Int(data_.n.i.i); if (IsInt()) return handler.Int(data_.n.i.i);
else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsUint()) return handler.Uint(data_.n.u.u);
else if (IsInt64()) return handler.Int64(data_.n.i64); else if (IsInt64()) return handler.Int64(data_.n.i64);
else if (IsUint64()) return handler.Uint64(data_.n.u64); else if (IsUint64()) return handler.Uint64(data_.n.u64);
else return handler.Double(data_.n.d); else return handler.Double(data_.n.d);
default:
RAPIDJSON_ASSERT(false);
} }
return false;
} }
private: private:
@ -1580,16 +1580,24 @@ private:
// Initialize this value as array with initial data, without calling destructor. // Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
flags_ = kArrayFlag; flags_ = kArrayFlag;
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); if (count) {
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
}
else
data_.a.elements = NULL;
data_.a.size = data_.a.capacity = count; data_.a.size = data_.a.capacity = count;
} }
//! Initialize this value as object with initial data, without calling destructor. //! Initialize this value as object with initial data, without calling destructor.
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
flags_ = kObjectFlag; flags_ = kObjectFlag;
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); if (count) {
std::memcpy(data_.o.members, members, count * sizeof(Member)); data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
std::memcpy(data_.o.members, members, count * sizeof(Member));
}
else
data_.o.members = NULL;
data_.o.size = data_.o.capacity = count; data_.o.size = data_.o.capacity = count;
} }
@ -1751,7 +1759,7 @@ public:
*/ */
template <unsigned parseFlags, typename InputStream> template <unsigned parseFlags, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { GenericDocument& ParseStream(InputStream& is) {
return ParseStream<parseFlags,Encoding,InputStream>(is); return ParseStream<parseFlags, Encoding, InputStream>(is);
} }
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags) //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
@ -1768,18 +1776,6 @@ public:
//!@name Parse in-place from mutable string //!@name Parse in-place from mutable string
//!@{ //!@{
//! Parse JSON text from a mutable string (with Encoding conversion)
/*! \tparam parseFlags Combination of \ref ParseFlag.
\tparam SourceEncoding Transcoding from input Encoding
\param str Mutable zero-terminated string to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& ParseInsitu(Ch* str) {
GenericInsituStringStream<Encoding> s(str);
return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s);
}
//! Parse JSON text from a mutable string //! Parse JSON text from a mutable string
/*! \tparam parseFlags Combination of \ref ParseFlag. /*! \tparam parseFlags Combination of \ref ParseFlag.
\param str Mutable zero-terminated string to be parsed. \param str Mutable zero-terminated string to be parsed.
@ -1787,7 +1783,8 @@ public:
*/ */
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& ParseInsitu(Ch* str) { GenericDocument& ParseInsitu(Ch* str) {
return ParseInsitu<parseFlags, Encoding>(str); GenericInsituStringStream<Encoding> s(str);
return ParseStream<parseFlags | kParseInsituFlag>(s);
} }
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
@ -1795,7 +1792,7 @@ public:
\return The document itself for fluent API. \return The document itself for fluent API.
*/ */
GenericDocument& ParseInsitu(Ch* str) { GenericDocument& ParseInsitu(Ch* str) {
return ParseInsitu<kParseDefaultFlags, Encoding>(str); return ParseInsitu<kParseDefaultFlags>(str);
} }
//!@} //!@}

View File

@ -109,6 +109,7 @@ public:
\param type UTF encoding type if it is not detected from the stream. \param type UTF encoding type if it is not detected from the stream.
*/ */
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType(); DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; takeFunc_ = f[type_];
@ -177,21 +178,8 @@ private:
} }
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
switch (type_) { if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
case kUTF8: if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
// Do nothing
break;
case kUTF16LE:
case kUTF16BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
break;
case kUTF32LE:
case kUTF32BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
default:
RAPIDJSON_ASSERT(false); // Invalid type
}
} }
typedef Ch (*TakeFunc)(InputByteStream& is); typedef Ch (*TakeFunc)(InputByteStream& is);
@ -220,22 +208,11 @@ public:
\param putBOM Whether to write BOM at the beginning of the stream. \param putBOM Whether to write BOM at the beginning of the stream.
*/ */
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion. RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
switch (type_) {
case kUTF16LE: // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
case kUTF16BE: if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
case kUTF32LE:
case kUTF32BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
case kUTF8:
// Do nothing
break;
default:
RAPIDJSON_ASSERT(false); // Invalid UTFType
}
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_]; putFunc_ = f[type_];

View File

@ -15,6 +15,8 @@
#ifndef RAPIDJSON_ERROR_ERROR_H__ #ifndef RAPIDJSON_ERROR_ERROR_H__
#define RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H__
#include "../rapidjson.h"
/*! \file error.h */ /*! \file error.h */
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */

View File

@ -1,67 +0,0 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILESTREAM_H_
#define RAPIDJSON_FILESTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! (Deprecated) Wrapper of C file stream for input or output.
/*!
This simple wrapper does not check the validity of the stream.
\note implements Stream concept
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
*/
class FileStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileStream(std::FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
char Peek() const { return current_; }
char Take() { char c = current_; Read(); return c; }
size_t Tell() const { return count_; }
void Put(char c) { fputc(c, fp_); }
void Flush() { fflush(fp_); }
// Not implemented
char* PutBegin() { return 0; }
size_t PutEnd(char*) { return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileStream(const FileStream&);
FileStream& operator=(const FileStream&);
void Read() {
RAPIDJSON_ASSERT(fp_ != 0);
int c = fgetc(fp_);
if (c != EOF) {
current_ = (char)c;
count_++;
}
else if (current_ != '\0')
current_ = '\0';
}
std::FILE* fp_;
char current_;
size_t count_;
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_

View File

@ -172,13 +172,10 @@ public:
} }
// Compute absolute difference of this and rhs. // Compute absolute difference of this and rhs.
// Return false if this < rhs // Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const { bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs); int cmp = Compare(rhs);
if (cmp == 0) { RAPIDJSON_ASSERT(cmp != 0);
*out = BigInteger(0);
return false;
}
const BigInteger *a, *b; // Makes a > b const BigInteger *a, *b; // Makes a > b
bool ret; bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; } if (cmp < 0) { a = &rhs; b = this; ret = true; }
@ -269,12 +266,6 @@ private:
#endif #endif
} }
static Type FullAdd(Type a, Type b, bool inCarry, bool* outCarry) {
Type c = a + b + (inCarry ? 1 : 0);
*outCarry = c < a;
return c;
}
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8; static const size_t kTypeBit = sizeof(Type) * 8;

View File

@ -19,12 +19,12 @@
#ifndef RAPIDJSON_DIYFP_H_ #ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_
#if defined(_MSC_VER) #include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> #include <intrin.h>
#if defined(_M_AMD64)
#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_BitScanReverse64)
#endif #endif
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
@ -135,25 +135,9 @@ struct DiyFp {
double d; double d;
uint64_t u64; uint64_t u64;
}u; }u;
uint64_t significand = f; const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
int exponent = e; static_cast<uint64_t>(e + kDpExponentBias);
while (significand > kDpHiddenBit + kDpSignificandMask) { u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
significand >>= 1;
exponent++;
}
while (exponent > kDpDenormalExponent && (significand & kDpHiddenBit) == 0) {
significand <<= 1;
exponent--;
}
if (exponent >= kDpMaxExponent) {
u.u64 = kDpExponentMask; // Infinity
return u.d;
}
else if (exponent < kDpDenormalExponent)
return 0.0;
const uint64_t be = (exponent == kDpDenormalExponent && (significand & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(exponent + kDpExponentBias);
u.u64 = (significand & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d; return u.d;
} }
@ -238,7 +222,7 @@ inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk); int k = static_cast<int>(dk);
if (k != dk) if (dk - k > 0.0)
k++; k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1); unsigned index = static_cast<unsigned>((k >> 3) + 1);

View File

@ -21,6 +21,7 @@
#include "itoa.h" // GetDigitsLut() #include "itoa.h" // GetDigitsLut()
#include "diyfp.h" #include "diyfp.h"
#include "ieee754.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
@ -49,8 +50,10 @@ inline unsigned CountDecimalDigit32(uint32_t n) {
if (n < 1000000) return 6; if (n < 1000000) return 6;
if (n < 10000000) return 7; if (n < 10000000) return 7;
if (n < 100000000) return 8; if (n < 100000000) return 8;
if (n < 1000000000) return 9; // Will not reach 10 digits in DigitGen()
return 10; //if (n < 1000000000) return 9;
//return 10;
return 9;
} }
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
@ -59,13 +62,12 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1); uint64_t p2 = Mp.f & (one.f - 1);
int kappa = CountDecimalDigit32(p1); int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while (kappa > 0) {
uint32_t d; uint32_t d = 0;
switch (kappa) { switch (kappa) {
case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
case 9: d = p1 / 100000000; p1 %= 100000000; break; case 9: d = p1 / 100000000; p1 %= 100000000; break;
case 8: d = p1 / 10000000; p1 %= 10000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break;
case 7: d = p1 / 1000000; p1 %= 1000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break;
@ -75,14 +77,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
case 3: d = p1 / 100; p1 %= 100; break; case 3: d = p1 / 100; p1 %= 100; break;
case 2: d = p1 / 10; p1 %= 10; break; case 2: d = p1 / 10; p1 %= 10; break;
case 1: d = p1; p1 = 0; break; case 1: d = p1; p1 = 0; break;
default: default:;
#if defined(_MSC_VER)
__assume(0);
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
__builtin_unreachable();
#else
d = 0;
#endif
} }
if (d || *len) if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
@ -192,7 +187,10 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
inline char* dtoa(double value, char* buffer) { inline char* dtoa(double value, char* buffer) {
if (value == 0) { Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
buffer[2] = '0'; buffer[2] = '0';

View File

@ -34,14 +34,6 @@ public:
return Double(u + 1).Value(); return Double(u + 1).Value();
} }
double PreviousPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign());
if (d == 0.0)
return 0.0;
else
return Double(u - 1).Value();
}
bool Sign() const { return (u & kSignMask) != 0; } bool Sign() const { return (u & kSignMask) != 0; }
uint64_t Significand() const { return u & kSignificandMask; } uint64_t Significand() const { return u & kSignificandMask; }
int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; } int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; }
@ -49,6 +41,7 @@ public:
bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; } bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; } bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }

View File

@ -15,6 +15,8 @@
#ifndef RAPIDJSON_ITOA_ #ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
@ -109,12 +111,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
} }
inline char* i32toa(int32_t value, char* buffer) { inline char* i32toa(int32_t value, char* buffer) {
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u32toa(static_cast<uint32_t>(value), buffer); return u32toa(u, buffer);
} }
inline char* u64toa(uint64_t value, char* buffer) { inline char* u64toa(uint64_t value, char* buffer) {
@ -286,12 +289,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
} }
inline char* i64toa(int64_t value, char* buffer) { inline char* i64toa(int64_t value, char* buffer) {
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u64toa(static_cast<uint64_t>(value), buffer); return u64toa(u, buffer);
} }
} // namespace internal } // namespace internal

View File

@ -15,9 +15,7 @@
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_
#ifndef RAPIDJSON_RAPIDJSON_H_ #include "../rapidjson.h"
#error <rapidjson.h> not yet included. Do not include this file directly.
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH

View File

@ -15,6 +15,8 @@
#ifndef RAPIDJSON_POW10_ #ifndef RAPIDJSON_POW10_
#define RAPIDJSON_POW10_ #define RAPIDJSON_POW10_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {

View File

@ -15,6 +15,8 @@
#ifndef RAPIDJSON_INTERNAL_STACK_H_ #ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {

View File

@ -15,6 +15,8 @@
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
#define RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {

View File

@ -52,7 +52,7 @@ inline T Min3(T a, T b, T c) {
return m; return m;
} }
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adjustToNegative) { inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b); const Double db(b);
const uint64_t bInt = db.IntegerSignificand(); const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent(); const int bExp = db.IntegerExponent();
@ -104,19 +104,9 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adj
hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
BigInteger delta(0); BigInteger delta(0);
*adjustToNegative = dS.Difference(bS, &delta); dS.Difference(bS, &delta);
int cmp = delta.Compare(hS); return delta.Compare(hS);
// If delta is within 1/2 ULP, check for special case when significand is power of two.
// In this case, need to compare with 1/2h in the lower bound.
if (cmp < 0 && *adjustToNegative && // within and dS < bS
db.IsNormal() && (bInt & (bInt - 1)) == 0 && // Power of 2
db.Uint64Value() != RAPIDJSON_UINT64_C2(0x00100000, 0x00000000)) // minimum normal number must not do this
{
delta <<= 1;
return delta.Compare(hS);
}
return cmp;
} }
inline bool StrtodFast(double d, int p, double* result) { inline bool StrtodFast(double d, int p, double* result) {
@ -213,24 +203,18 @@ inline double StrtodBigInteger(double approx, const char* decimals, size_t lengt
const BigInteger dInt(decimals, length); const BigInteger dInt(decimals, length);
const int dExp = (int)decimalPosition - (int)length + exp; const int dExp = (int)decimalPosition - (int)length + exp;
Double a(approx); Double a(approx);
for (int i = 0; i < 10; i++) { int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
bool adjustToNegative; if (cmp < 0)
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp, &adjustToNegative); return a.Value(); // within half ULP
if (cmp < 0) else if (cmp == 0) {
return a.Value(); // within half ULP // Round towards even
else if (cmp == 0) { if (a.Significand() & 1)
// Round towards even return a.NextPositiveDouble();
if (a.Significand() & 1) else
return adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble(); return a.Value();
else
return a.Value();
}
else // adjustment
a = adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble();
} }
else // adjustment
// This should not happen, but in case there is really a bug, break the infinite-loop return a.NextPositiveDouble();
return a.Value();
} }
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
@ -258,7 +242,9 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
// Trim right-most digits // Trim right-most digits
const int kMaxDecimalDigit = 780; const int kMaxDecimalDigit = 780;
if ((int)length > kMaxDecimalDigit) { if ((int)length > kMaxDecimalDigit) {
exp += (int(length) - kMaxDecimalDigit); int delta = (int(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= delta;
length = kMaxDecimalDigit; length = kMaxDecimalDigit;
} }

View File

@ -78,7 +78,7 @@ public:
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) { bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size())); return String(str.data(), SizeType(str.size()));
} }
#endif #endif
@ -100,8 +100,9 @@ public:
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
if (!Base::WriteEndObject()) bool ret = Base::WriteEndObject();
return false; (void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush(); Base::os_->Flush();
return true; return true;
@ -123,8 +124,9 @@ public:
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
if (!Base::WriteEndArray()) bool ret = Base::WriteEndArray();
return false; (void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush(); Base::os_->Flush();
return true; return true;

View File

@ -15,12 +15,9 @@
#ifndef RAPIDJSON_RAPIDJSON_H_ #ifndef RAPIDJSON_RAPIDJSON_H_
#define RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
// Version 0.1
/*!\file rapidjson.h /*!\file rapidjson.h
\brief common definitions and configuration \brief common definitions and configuration
\see RAPIDJSON_CONFIG \see RAPIDJSON_CONFIG
*/ */
@ -42,6 +39,40 @@
#include <cstdlib> // malloc(), realloc(), free(), size_t #include <cstdlib> // malloc(), realloc(), free(), size_t
#include <cstring> // memset(), memcpy(), memmove(), memcmp() #include <cstring> // memset(), memcpy(), memmove(), memcmp()
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_VERSION_STRING
//
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
//
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
//!@endcond
/*! \def RAPIDJSON_MAJOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Major version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_MINOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Minor version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_PATCH_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Patch version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_VERSION_STRING
\ingroup RAPIDJSON_CONFIG
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
*/
#define RAPIDJSON_MAJOR_VERSION 1
#define RAPIDJSON_MINOR_VERSION 0
#define RAPIDJSON_PATCH_VERSION 1
#define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NAMESPACE_(BEGIN|END) // RAPIDJSON_NAMESPACE_(BEGIN|END)
/*! \def RAPIDJSON_NAMESPACE /*! \def RAPIDJSON_NAMESPACE
@ -122,9 +153,9 @@
#ifndef RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __forceinline #define RAPIDJSON_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ >= 4 #elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
#else #else
#define RAPIDJSON_FORCEINLINE #define RAPIDJSON_FORCEINLINE
@ -356,10 +387,6 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_VERSION_CODE(x,y,z) \ #define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z)) (((x)*100000) + ((y)*100) + (z))
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF

View File

@ -255,23 +255,23 @@ void SkipWhitespace(InputStream& is) {
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return 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_load_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);
@ -292,31 +292,31 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// The rest of string // The rest of string
static const char whitespaces[4][17] = { static const char whitespaces[4][17] = {
" ", " ",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][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);
@ -689,11 +689,13 @@ private:
} }
else if (e == 'u') { // Unicode else if (e == 'u') { // Unicode
unsigned codepoint = ParseHex4(is); unsigned codepoint = ParseHex4(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
// Handle UTF-16 surrogate pair // Handle UTF-16 surrogate pair
if (is.Take() != '\\' || is.Take() != 'u') if (is.Take() != '\\' || is.Take() != 'u')
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
unsigned codepoint2 = ParseHex4(is); unsigned codepoint2 = ParseHex4(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
@ -894,7 +896,7 @@ private:
if (significandDigit < 17) { if (significandDigit < 17) {
d = d * 10.0 + (s.TakePush() - '0'); d = d * 10.0 + (s.TakePush() - '0');
--expFrac; --expFrac;
if (d != 0.0) if (d > 0.0)
significandDigit++; significandDigit++;
} }
else else
@ -923,10 +925,22 @@ private:
if (s.Peek() >= '0' && s.Peek() <= '9') { if (s.Peek() >= '0' && s.Peek() <= '9') {
exp = s.Take() - '0'; exp = s.Take() - '0';
while (s.Peek() >= '0' && s.Peek() <= '9') { if (expMinus) {
exp = exp * 10 + (s.Take() - '0'); while (s.Peek() >= '0' && s.Peek() <= '9') {
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. exp = exp * 10 + (s.Take() - '0');
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); if (exp >= 214748364) { // Issue #313: prevent overflow exponent
while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent
s.Take();
}
}
}
else { // positive exp
int maxExp = 308 - expFrac;
while (s.Peek() >= '0' && s.Peek() <= '9') {
exp = exp * 10 + (s.Take() - '0');
if (exp > maxExp)
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
}
} }
} }
else else
@ -1225,14 +1239,9 @@ private:
// May return a new state on state pop. // May return a new state on state pop.
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
(void)token;
switch (dst) { switch (dst) {
case IterativeParsingStartState:
RAPIDJSON_ASSERT(false);
return IterativeParsingErrorState;
case IterativeParsingFinishState:
return dst;
case IterativeParsingErrorState: case IterativeParsingErrorState:
return dst; return dst;
@ -1271,12 +1280,9 @@ private:
return dst; return dst;
case IterativeParsingKeyValueDelimiterState: case IterativeParsingKeyValueDelimiterState:
if (token == ColonToken) { RAPIDJSON_ASSERT(token == ColonToken);
is.Take(); is.Take();
return dst; return dst;
}
else
return IterativeParsingErrorState;
case IterativeParsingMemberValueState: case IterativeParsingMemberValueState:
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
@ -1351,17 +1357,25 @@ private:
} }
} }
case IterativeParsingValueState: default:
// This branch is for IterativeParsingValueState actually.
// Use `default:` rather than
// `case IterativeParsingValueState:` is for code coverage.
// The IterativeParsingStartState is not enumerated in this switch-case.
// It is impossible for that case. And it can be caught by following assertion.
// The IterativeParsingFinishState is not enumerated in this switch-case either.
// It is a "derivative" state which cannot triggered from Predict() directly.
// Therefore it cannot happen here. And it can be caught by following assertion.
RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
if (HasParseError()) { if (HasParseError()) {
return IterativeParsingErrorState; return IterativeParsingErrorState;
} }
return IterativeParsingFinishState; return IterativeParsingFinishState;
default:
RAPIDJSON_ASSERT(false);
return IterativeParsingErrorState;
} }
} }

View File

@ -127,7 +127,7 @@ public:
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) { bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size())); return String(str.data(), SizeType(str.size()));
} }
#endif #endif
@ -272,7 +272,8 @@ protected:
os_->Put(hexDigits[(codepoint >> 4) & 15]); os_->Put(hexDigits[(codepoint >> 4) & 15]);
os_->Put(hexDigits[(codepoint ) & 15]); os_->Put(hexDigits[(codepoint ) & 15]);
} }
else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) { else {
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
// Surrogate pair // Surrogate pair
unsigned s = codepoint - 0x010000; unsigned s = codepoint - 0x010000;
unsigned lead = (s >> 10) + 0xD800; unsigned lead = (s >> 10) + 0xD800;
@ -288,8 +289,6 @@ protected:
os_->Put(hexDigits[(trail >> 4) & 15]); os_->Put(hexDigits[(trail >> 4) & 15]);
os_->Put(hexDigits[(trail ) & 15]); os_->Put(hexDigits[(trail ) & 15]);
} }
else
return false; // invalid code point
} }
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
is.Take(); is.Take();
@ -303,7 +302,8 @@ protected:
} }
} }
else else
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_); if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
return false;
} }
os_->Put('\"'); os_->Put('\"');
return true; return true;

View File

@ -1,4 +1,7 @@
![](doc/logo/rapidjson.png) ![](doc/logo/rapidjson.png)
![](https://img.shields.io/badge/release-v1.0.1-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
Tencent is pleased to support the open source community by making RapidJSON available. Tencent is pleased to support the open source community by making RapidJSON available.
@ -13,14 +16,16 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
## Build status ## Build status
| [Linux][lin-link] | [Windows][win-link] | | [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] |
| :---------------: | :-----------------: | | :---------------: | :-----------------: | :-------------------: |
| ![lin-badge] | ![win-badge] | | ![lin-badge] | ![win-badge] | ![cov-badge] |
[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png "Travis build status" [lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" [lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master?svg=true "AppVeyor build status" [win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
## Introduction ## Introduction
@ -28,7 +33,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](
* RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. * RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.1 for acceleration. * RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
* RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL. * RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL.

View File

@ -1,5 +1,9 @@
![](doc/logo/rapidjson.png) ![](doc/logo/rapidjson.png)
![](https://img.shields.io/badge/release-v1.0.1-blue.png)
## 高效的C++ JSON解析生成器提供SAX及DOM风格API
Tencent is pleased to support the open source community by making RapidJSON available. Tencent is pleased to support the open source community by making RapidJSON available.
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
@ -10,13 +14,26 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
* [简体中文](http://miloyip.github.io/rapidjson/zh-cn/) * [简体中文](http://miloyip.github.io/rapidjson/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 状态
| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] |
| :---------------: | :-----------------: | :-------------------: |
| ![lin-badge] | ![win-badge] | ![cov-badge] |
[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
## 简介 ## 简介
RapidJSON是一个C++的JSON解析器及生成器。它的灵感来自[RapidXml](http://rapidxml.sourceforge.net/)。 RapidJSON是一个C++的JSON解析器及生成器。它的灵感来自[RapidXml](http://rapidxml.sourceforge.net/)。
* RapidJSON小而全。它同时支持SAX和DOM风格的API。SAX解析器只有约500行代码。 * RapidJSON小而全。它同时支持SAX和DOM风格的API。SAX解析器只有约500行代码。
* RapidJSON快。它的性能可与`strlen()`相比。可支持SSE2/SSE4.1加速。 * RapidJSON快。它的性能可与`strlen()`相比。可支持SSE2/SSE4.2加速。
* RapidJSON独立。它不依赖于BOOST等外部库。它甚至不依赖于STL。 * RapidJSON独立。它不依赖于BOOST等外部库。它甚至不依赖于STL。
@ -45,21 +62,21 @@ RapidJSON是跨平台的。以下是一些曾测试的平台编译器组合
RapidJSON是只有头文件的C++库。只需把`include/rapidjson`目录复制至系统或项目的include目录中。 RapidJSON是只有头文件的C++库。只需把`include/rapidjson`目录复制至系统或项目的include目录中。
RapidJSON依赖于以下软件
* [CMake](http://www.cmake.org) 作为通用生成工具
* (optional)[Doxygen](http://www.doxygen.org)用于生成文档
* (optional)[googletest](https://code.google.com/p/googletest/)用于单元及性能测试
生成测试及例子的步骤: 生成测试及例子的步骤:
1. 执行 `git submodule update --init` 去获取 thirdparty submodules (google test)。 1. 执行 `git submodule update --init` 去获取 thirdparty submodules (google test)。
2. 下载 [premake4](http://industriousone.com/premake/download)。 2. 在rapidjson目渌下建立一个`build`目录。
3. 复制 premake4 可执行文件至 `rapidjson/build` (或系统路径)。 3. 在`build`目录下执行`cmake ..`命令以设置生成。Windows用户可使用cmake-gui应用程序。
4. 进入`rapidjson/build/`目录在Windows下执行`premake.bat`在Linux或其他平台下执行`premake.sh` 4. 在Windows下编译生成在build目录中的solution。在Linux下于build目录运行`make`
5. 在Windows上生成位于`rapidjson/build/vs2008/``/vs2010/`内的项目方案.
6. 在其他平台上,在`rapidjson/build/gmake/`目录执行GNU `make`(如 `make -f test.make config=release32``make -f example.make config=debug32`)。
7. 若成功,可执行文件会生成在`rapidjson/bin`目录。
生成[Doxygen](http://doxygen.org)文档的步骤: 成功生成后,你会在`bin`的目录下找到编译后的测试及例子可执行文件。而生成的文档将位于build下的`doc/html`目录。要执行测试请在build下执行`make test``ctest`。使用`ctest -V`命令可获取详细的输出。
1. 下载及安装[Doxygen](http://doxygen.org/download.html)。 我们也可以把程序库安装至全系统中只要在具管理權限下从build目录执行`make install`命令。这样会按系统的偏好设置安装所有文件。当安装RapidJSON后其他的CMake项目需要使用它时可以通过在`CMakeLists.txt`加入一句`find_package(RapidJSON)`
2. 在顶层目录执行`doxygen build/Doxyfile`
3. 在`doc/html`浏览文档。
## 用法一览 ## 用法一览

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "perftest.h" #include "perftest.h"
@ -768,7 +762,7 @@ template <typename Writer>
void itoa_Writer_StringBufferVerify() { void itoa_Writer_StringBufferVerify() {
rapidjson::StringBuffer sb; rapidjson::StringBuffer sb;
Writer writer(sb); Writer writer(sb);
for (int j = 0; j < randvalCount; j++) { for (size_t j = 0; j < randvalCount; j++) {
char buffer[32]; char buffer[32];
sprintf(buffer, "%d", randval[j]); sprintf(buffer, "%d", randval[j]);
writer.WriteInt(randval[j]); writer.WriteInt(randval[j]);
@ -780,7 +774,7 @@ void itoa_Writer_StringBufferVerify() {
template <typename Writer> template <typename Writer>
void itoa_Writer_InsituStringStreamVerify() { void itoa_Writer_InsituStringStreamVerify() {
Writer writer; Writer writer;
for (int j = 0; j < randvalCount; j++) { for (size_t j = 0; j < randvalCount; j++) {
char buffer[32]; char buffer[32];
sprintf(buffer, "%d", randval[j]); sprintf(buffer, "%d", randval[j]);
char buffer2[32]; char buffer2[32];

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "perftest.h" #include "perftest.h"

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef PERFTEST_H_ #ifndef PERFTEST_H_
#define PERFTEST_H_ #define PERFTEST_H_
@ -71,9 +65,20 @@ public:
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {} PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
virtual void SetUp() { virtual void SetUp() {
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
if (!fp) const char *paths[] = {
fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); "data/sample.json",
"bin/data/sample.json",
"../bin/data/sample.json",
"../../bin/data/sample.json",
"../../../bin/data/sample.json"
};
FILE *fp = 0;
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
fp = fopen(filename_ = paths[i], "rb");
if (fp)
break;
}
ASSERT_TRUE(fp != 0); ASSERT_TRUE(fp != 0);
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "perftest.h" #include "perftest.h"

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "perftest.h" #include "perftest.h"
@ -26,7 +20,6 @@
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/prettywriter.h" #include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "rapidjson/filestream.h"
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"
#include "rapidjson/encodedstream.h" #include "rapidjson/encodedstream.h"
#include "rapidjson/memorystream.h" #include "rapidjson/memorystream.h"
@ -324,17 +317,6 @@ TEST_F(RapidJson, UTF8_Validate) {
} }
} }
// Deprecated.
//TEST_F(RapidJson, FileStream_Read) {
// for (size_t i = 0; i < kTrialCount; i++) {
// FILE *fp = fopen(filename_, "rb");
// FileStream s(fp);
// while (s.Take() != '\0')
// ;
// fclose(fp);
// }
//}
TEST_F(RapidJson, FileReadStream) { TEST_F(RapidJson, FileReadStream) {
for (size_t i = 0; i < kTrialCount; i++) { for (size_t i = 0; i < kTrialCount; i++) {
FILE *fp = fopen(filename_, "rb"); FILE *fp = fopen(filename_, "rb");

View File

@ -1,13 +1,20 @@
set(UNITTEST_SOURCES set(UNITTEST_SOURCES
allocatorstest.cpp
bigintegertest.cpp bigintegertest.cpp
documenttest.cpp documenttest.cpp
encodedstreamtest.cpp encodedstreamtest.cpp
encodingstest.cpp encodingstest.cpp
filestreamtest.cpp filestreamtest.cpp
itoatest.cpp
jsoncheckertest.cpp jsoncheckertest.cpp
namespacetest.cpp namespacetest.cpp
<<<<<<< HEAD
pointertest.cpp pointertest.cpp
=======
prettywritertest.cpp
>>>>>>> master
readertest.cpp readertest.cpp
simdtest.cpp
stringbuffertest.cpp stringbuffertest.cpp
strtodtest.cpp strtodtest.cpp
unittest.cpp unittest.cpp
@ -15,9 +22,9 @@ set(UNITTEST_SOURCES
writertest.cpp) writertest.cpp)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Weffc++ -Wswitch-default") 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 -Weffc++ -Wswitch-default") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
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()
@ -36,8 +43,9 @@ add_test(NAME unittest
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(NOT MSVC) if(NOT MSVC)
# Not running SIMD.* unit test cases for Valgrind
add_test(NAME valgrind_unittest add_test(NAME valgrind_unittest
COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")

View File

@ -0,0 +1,60 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
#include "rapidjson/allocators.h"
using namespace rapidjson;
template <typename Allocator>
void TestAllocator(Allocator& a) {
EXPECT_TRUE(a.Malloc(0) == 0);
uint8_t* p = (uint8_t*)a.Malloc(100);
EXPECT_TRUE(p != 0);
for (size_t i = 0; i < 100; i++)
p[i] = (uint8_t)i;
// Expand
uint8_t* q = (uint8_t*)a.Realloc(p, 100, 200);
EXPECT_TRUE(q != 0);
for (size_t i = 0; i < 100; i++)
EXPECT_EQ(i, q[i]);
for (size_t i = 100; i < 200; i++)
q[i] = (uint8_t)i;
// Shrink
uint8_t *r = (uint8_t*)a.Realloc(q, 200, 150);
EXPECT_TRUE(r != 0);
for (size_t i = 0; i < 150; i++)
EXPECT_EQ(i, r[i]);
Allocator::Free(r);
}
TEST(Allocator, CrtAllocator) {
CrtAllocator a;
TestAllocator(a);
}
TEST(Allocator, MemoryPoolAllocator) {
MemoryPoolAllocator<> a;
TestAllocator(a);
for (int i = 1; i < 1000; i++) {
EXPECT_TRUE(a.Malloc(i) != 0);
EXPECT_LE(a.Size(), a.Capacity());
}
}

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/document.h" #include "rapidjson/document.h"
@ -28,13 +22,11 @@
using namespace rapidjson; using namespace rapidjson;
template <typename Allocator, typename StackAllocator> template <typename DocumentType>
void ParseTest() { void ParseCheck(DocumentType& doc) {
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
typedef typename DocumentType::ValueType ValueType; typedef typename DocumentType::ValueType ValueType;
DocumentType doc;
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_TRUE(doc.IsObject()); EXPECT_TRUE(doc.IsObject());
@ -63,7 +55,7 @@ void ParseTest() {
EXPECT_TRUE(doc.HasMember("pi")); EXPECT_TRUE(doc.HasMember("pi"));
const ValueType& pi = doc["pi"]; const ValueType& pi = doc["pi"];
EXPECT_TRUE(pi.IsNumber()); EXPECT_TRUE(pi.IsNumber());
EXPECT_EQ(3.1416, pi.GetDouble()); EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
EXPECT_TRUE(doc.HasMember("a")); EXPECT_TRUE(doc.HasMember("a"));
const ValueType& a = doc["a"]; const ValueType& a = doc["a"];
@ -73,6 +65,28 @@ void ParseTest() {
EXPECT_EQ(i + 1, a[i].GetUint()); EXPECT_EQ(i + 1, a[i].GetUint());
} }
template <typename Allocator, typename StackAllocator>
void ParseTest() {
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
DocumentType doc;
const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
doc.Parse(json);
ParseCheck(doc);
doc.SetNull();
StringStream s(json);
doc.template ParseStream<0>(s);
ParseCheck(doc);
doc.SetNull();
char *buffer = strdup(json);
doc.ParseInsitu(buffer);
ParseCheck(doc);
free(buffer);
}
TEST(Document, Parse) { TEST(Document, Parse) {
ParseTest<MemoryPoolAllocator<>, CrtAllocator>(); ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >(); ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
@ -81,14 +95,21 @@ TEST(Document, Parse) {
} }
static FILE* OpenEncodedFile(const char* filename) { static FILE* OpenEncodedFile(const char* filename) {
const char *paths[] = {
"encodings/%s",
"bin/encodings/%s",
"../bin/encodings/%s",
"../../bin/encodings/%s",
"../../../bin/encodings/%s"
};
char buffer[1024]; char buffer[1024];
sprintf(buffer, "encodings/%s", filename); for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
FILE *fp = fopen(buffer, "rb"); sprintf(buffer, paths[i], filename);
if (!fp) { FILE *fp = fopen(buffer, "rb");
sprintf(buffer, "../../bin/encodings/%s", filename); if (fp)
fp = fopen(buffer, "rb"); return fp;
} }
return fp; return 0;
} }
TEST(Document, ParseStream_EncodedInputStream) { TEST(Document, ParseStream_EncodedInputStream) {
@ -223,6 +244,10 @@ TEST(Document, UserBuffer) {
EXPECT_FALSE(doc.HasParseError()); EXPECT_FALSE(doc.HasParseError());
EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer)); EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer)); EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
// Cover MemoryPoolAllocator::Capacity()
EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
} }
// Issue 226: Value of string type should not point to NULL // Issue 226: Value of string type should not point to NULL

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"
@ -47,14 +41,21 @@ private:
protected: protected:
static FILE* Open(const char* filename) { static FILE* Open(const char* filename) {
const char *paths[] = {
"encodings/%s",
"bin/encodings/%s",
"../bin/encodings/%s",
"../../bin/encodings/%s",
"../../../bin/encodings/%s"
};
char buffer[1024]; char buffer[1024];
sprintf(buffer, "encodings/%s", filename); for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
FILE *fp = fopen(buffer, "rb"); sprintf(buffer, paths[i], filename);
if (!fp) { FILE *fp = fopen(buffer, "rb");
sprintf(buffer, "../../bin/encodings/%s", filename); if (fp)
fp = fopen(buffer, "rb"); return fp;
} }
return fp; return 0;
} }
static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) { static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) {
@ -112,10 +113,11 @@ protected:
} }
EXPECT_EQ('\0', s.Peek()); EXPECT_EQ('\0', s.Peek());
free(data); free(data);
EXPECT_EQ(size, eis.Tell());
} }
} }
void TestAutoUTFInputStream(const char *filename) { void TestAutoUTFInputStream(const char *filename, bool expectHasBOM) {
// Test FileReadStream // Test FileReadStream
{ {
char buffer[16]; char buffer[16];
@ -123,6 +125,7 @@ protected:
ASSERT_TRUE(fp != 0); ASSERT_TRUE(fp != 0);
FileReadStream fs(fp, buffer, sizeof(buffer)); FileReadStream fs(fp, buffer, sizeof(buffer));
AutoUTFInputStream<unsigned, FileReadStream> eis(fs); AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
EXPECT_EQ(expectHasBOM, eis.HasBOM());
StringStream s(json_); StringStream s(json_);
while (eis.Peek() != '\0') { while (eis.Peek() != '\0') {
unsigned expected, actual; unsigned expected, actual;
@ -140,6 +143,7 @@ protected:
char* data = ReadFile(filename, true, &size); char* data = ReadFile(filename, true, &size);
MemoryStream ms(data, size); MemoryStream ms(data, size);
AutoUTFInputStream<unsigned, MemoryStream> eis(ms); AutoUTFInputStream<unsigned, MemoryStream> eis(ms);
EXPECT_EQ(expectHasBOM, eis.HasBOM());
StringStream s(json_); StringStream s(json_);
while (eis.Peek() != '\0') { while (eis.Peek() != '\0') {
@ -150,6 +154,7 @@ protected:
} }
EXPECT_EQ('\0', s.Peek()); EXPECT_EQ('\0', s.Peek());
free(data); free(data);
EXPECT_EQ(size, eis.Tell());
} }
} }
@ -257,16 +262,25 @@ TEST_F(EncodedStreamTest, EncodedInputStream) {
} }
TEST_F(EncodedStreamTest, AutoUTFInputStream) { TEST_F(EncodedStreamTest, AutoUTFInputStream) {
TestAutoUTFInputStream("utf8.json"); TestAutoUTFInputStream("utf8.json", false);
TestAutoUTFInputStream("utf8bom.json"); TestAutoUTFInputStream("utf8bom.json", true);
TestAutoUTFInputStream("utf16le.json"); TestAutoUTFInputStream("utf16le.json", false);
TestAutoUTFInputStream("utf16lebom.json"); TestAutoUTFInputStream("utf16lebom.json",true);
TestAutoUTFInputStream("utf16be.json"); TestAutoUTFInputStream("utf16be.json", false);
TestAutoUTFInputStream("utf16bebom.json"); TestAutoUTFInputStream("utf16bebom.json",true);
TestAutoUTFInputStream("utf32le.json"); TestAutoUTFInputStream("utf32le.json", false);
TestAutoUTFInputStream("utf32lebom.json"); TestAutoUTFInputStream("utf32lebom.json",true);
TestAutoUTFInputStream("utf32be.json"); TestAutoUTFInputStream("utf32be.json", false);
TestAutoUTFInputStream("utf32bebom.json"); TestAutoUTFInputStream("utf32bebom.json", true);
{
// Auto detection fail, use user defined UTF type
const char json[] = "{ }";
MemoryStream ms(json, sizeof(json));
AutoUTFInputStream<unsigned, MemoryStream> eis(ms, kUTF8);
EXPECT_FALSE(eis.HasBOM());
EXPECT_EQ(kUTF8, eis.GetType());
}
} }
TEST_F(EncodedStreamTest, EncodedOutputStream) { TEST_F(EncodedStreamTest, EncodedOutputStream) {

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"

View File

@ -1,25 +1,18 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/filestream.h"
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h" #include "rapidjson/filewritestream.h"
#include "rapidjson/encodedstream.h" #include "rapidjson/encodedstream.h"
@ -31,9 +24,21 @@ public:
FileStreamTest() : filename_(), json_(), length_() {} FileStreamTest() : filename_(), json_(), length_() {}
virtual void SetUp() { virtual void SetUp() {
FILE *fp = fopen(filename_ = "data/sample.json", "rb"); const char *paths[] = {
if (!fp) "data/sample.json",
fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); "bin/data/sample.json",
"../bin/data/sample.json",
"../../bin/data/sample.json",
"../../../bin/data/sample.json"
};
FILE* fp = 0;
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
fp = fopen(paths[i], "rb");
if (fp) {
filename_ = paths[i];
break;
}
}
ASSERT_TRUE(fp != 0); ASSERT_TRUE(fp != 0);
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
@ -60,24 +65,6 @@ protected:
size_t length_; size_t length_;
}; };
// Deprecated
//TEST_F(FileStreamTest, FileStream_Read) {
// FILE *fp = fopen(filename_, "rb");
// ASSERT_TRUE(fp != 0);
// FileStream s(fp);
//
// for (size_t i = 0; i < length_; i++) {
// EXPECT_EQ(json_[i], s.Peek());
// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
// EXPECT_EQ(json_[i], s.Take());
// }
//
// EXPECT_EQ(length_, s.Tell());
// EXPECT_EQ('\0', s.Peek());
//
// fclose(fp);
//}
TEST_F(FileStreamTest, FileReadStream) { TEST_F(FileStreamTest, FileReadStream) {
FILE *fp = fopen(filename_, "rb"); FILE *fp = fopen(filename_, "rb");
ASSERT_TRUE(fp != 0); ASSERT_TRUE(fp != 0);

158
test/unittest/itoatest.cpp Normal file
View File

@ -0,0 +1,158 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
#include "rapidjson/internal/itoa.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(type-limits)
#endif
using namespace rapidjson::internal;
template <typename T>
struct Traits {
};
template <>
struct Traits<uint32_t> {
enum { kBufferSize = 11 };
enum { kMaxDigit = 10 };
static uint32_t Negate(uint32_t x) { return x; };
};
template <>
struct Traits<int32_t> {
enum { kBufferSize = 12 };
enum { kMaxDigit = 10 };
static int32_t Negate(int32_t x) { return -x; };
};
template <>
struct Traits<uint64_t> {
enum { kBufferSize = 21 };
enum { kMaxDigit = 20 };
static uint64_t Negate(uint64_t x) { return x; };
};
template <>
struct Traits<int64_t> {
enum { kBufferSize = 22 };
enum { kMaxDigit = 20 };
static int64_t Negate(int64_t x) { return -x; };
};
template <typename T>
static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
char buffer1[Traits<T>::kBufferSize];
char buffer2[Traits<T>::kBufferSize];
f(value, buffer1);
*g(value, buffer2) = '\0';
EXPECT_STREQ(buffer1, buffer2);
}
template <typename T>
static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
// Boundary cases
VerifyValue<T>(0, f, g);
VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
// 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
for (uint32_t power = 2; power <= 10; power += 8) {
T i = 1, last;
do {
VerifyValue<T>(i - 1, f, g);
VerifyValue<T>(i, f, g);
if (std::numeric_limits<T>::min() < 0) {
VerifyValue<T>(Traits<T>::Negate(i), f, g);
VerifyValue<T>(Traits<T>::Negate(i + 1), f, g);
}
last = i;
i *= power;
} while (last < i);
}
}
static void u32toa_naive(uint32_t value, char* buffer) {
char temp[10];
char *p = temp;
do {
*p++ = char(value % 10) + '0';
value /= 10;
} while (value > 0);
do {
*buffer++ = *--p;
} while (p != temp);
*buffer = '\0';
}
static void i32toa_naive(int32_t value, char* buffer) {
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
u32toa_naive(u, buffer);
}
static void u64toa_naive(uint64_t value, char* buffer) {
char temp[20];
char *p = temp;
do {
*p++ = char(value % 10) + '0';
value /= 10;
} while (value > 0);
do {
*buffer++ = *--p;
} while (p != temp);
*buffer = '\0';
}
static void i64toa_naive(int64_t value, char* buffer) {
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
u64toa_naive(u, buffer);
}
TEST(itoa, u32toa) {
Verify(u32toa_naive, u32toa);
}
TEST(itoa, i32toa) {
Verify(i32toa_naive, i32toa);
}
TEST(itoa, u64toa) {
Verify(u64toa_naive, u64toa);
}
TEST(itoa, i64toa) {
Verify(i64toa_naive, i64toa);
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
@ -25,9 +19,22 @@
using namespace rapidjson; using namespace rapidjson;
static char* ReadFile(const char* filename, size_t& length) { static char* ReadFile(const char* filename, size_t& length) {
FILE *fp = fopen(filename, "rb"); const char *paths[] = {
if (!fp) "jsonchecker/%s",
fp = fopen(filename, "rb"); "bin/jsonchecker/%s",
"../bin/jsonchecker/%s",
"../../bin/jsonchecker/%s",
"../../../bin/jsonchecker/%s"
};
char buffer[1024];
FILE *fp = 0;
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
sprintf(buffer, paths[i], filename);
fp = fopen(buffer, "rb");
if (fp)
break;
}
if (!fp) if (!fp)
return 0; return 0;
@ -51,17 +58,13 @@ TEST(JsonChecker, Reader) {
if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting. if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
continue; continue;
sprintf(filename, "jsonchecker/fail%d.json", i); sprintf(filename, "fail%d.json", i);
size_t length; size_t length;
char* json = ReadFile(filename, length); char* json = ReadFile(filename, length);
if (!json) { if (!json) {
sprintf(filename, "../../bin/jsonchecker/fail%d.json", i); printf("jsonchecker file %s not found", filename);
json = ReadFile(filename, length); ADD_FAILURE();
if (!json) { continue;
printf("jsonchecker file %s not found", filename);
ADD_FAILURE();
continue;
}
} }
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
@ -76,16 +79,12 @@ TEST(JsonChecker, Reader) {
// passX.json // passX.json
for (int i = 1; i <= 3; i++) { for (int i = 1; i <= 3; i++) {
sprintf(filename, "jsonchecker/pass%d.json", i); sprintf(filename, "pass%d.json", i);
size_t length; size_t length;
char* json = ReadFile(filename, length); char* json = ReadFile(filename, length);
if (!json) { if (!json) {
sprintf(filename, "../../bin/jsonchecker/pass%d.json", i); printf("jsonchecker file %s not found", filename);
json = ReadFile(filename, length); continue;
if (!json) {
printf("jsonchecker file %s not found", filename);
continue;
}
} }
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"

View File

@ -0,0 +1,161 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
#include "rapidjson/reader.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h"
using namespace rapidjson;
static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}";
static const char kPrettyJson[] =
"{\n"
" \"hello\": \"world\",\n"
" \"t\": true,\n"
" \"f\": false,\n"
" \"n\": null,\n"
" \"i\": 123,\n"
" \"pi\": 3.1416,\n"
" \"a\": [\n"
" 1,\n"
" 2,\n"
" 3,\n"
" -1\n"
" ],\n"
" \"u64\": 1234567890123456789,\n"
" \"i64\": -1234567890123456789\n"
"}";
TEST(PrettyWriter, Basic) {
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
Reader reader;
StringStream s(kJson);
reader.Parse(s, writer);
EXPECT_STREQ(kPrettyJson, buffer.GetString());
}
TEST(PrettyWriter, SetIndent) {
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.SetIndent('\t', 1);
Reader reader;
StringStream s(kJson);
reader.Parse(s, writer);
EXPECT_STREQ(
"{\n"
"\t\"hello\": \"world\",\n"
"\t\"t\": true,\n"
"\t\"f\": false,\n"
"\t\"n\": null,\n"
"\t\"i\": 123,\n"
"\t\"pi\": 3.1416,\n"
"\t\"a\": [\n"
"\t\t1,\n"
"\t\t2,\n"
"\t\t3,\n"
"\t\t-1\n"
"\t],\n"
"\t\"u64\": 1234567890123456789,\n"
"\t\"i64\": -1234567890123456789\n"
"}",
buffer.GetString());
}
TEST(PrettyWriter, String) {
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
EXPECT_TRUE(writer.StartArray());
EXPECT_TRUE(writer.String("Hello\n"));
EXPECT_TRUE(writer.EndArray());
EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
}
#if RAPIDJSON_HAS_STDSTRING
TEST(PrettyWriter, String_STDSTRING) {
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
EXPECT_TRUE(writer.StartArray());
EXPECT_TRUE(writer.String(std::string("Hello\n")));
EXPECT_TRUE(writer.EndArray());
EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
}
#endif
#include <sstream>
class OStreamWrapper {
public:
typedef char Ch;
OStreamWrapper(std::ostream& os) : os_(os) {}
Ch Peek() const { assert(false); return '\0'; }
Ch Take() { assert(false); return '\0'; }
size_t Tell() const { return 0; }
Ch* PutBegin() { assert(false); return 0; }
void Put(Ch c) { os_.put(c); }
void Flush() { os_.flush(); }
size_t PutEnd(Ch*) { assert(false); return 0; }
private:
OStreamWrapper(const OStreamWrapper&);
OStreamWrapper& operator=(const OStreamWrapper&);
std::ostream& os_;
};
// For covering PutN() generic version
TEST(PrettyWriter, OStreamWrapper) {
StringStream s(kJson);
std::stringstream ss;
OStreamWrapper os(ss);
PrettyWriter<OStreamWrapper> writer(os);
Reader reader;
reader.Parse(s, writer);
std::string actual = ss.str();
EXPECT_STREQ(kPrettyJson, actual.c_str());
}
// For covering FileWriteStream::PutN()
TEST(PrettyWriter, FileWriteStream) {
char filename[L_tmpnam];
FILE* fp = TempFile(filename);
char buffer[16];
FileWriteStream os(fp, buffer, sizeof(buffer));
PrettyWriter<FileWriteStream> writer(os);
Reader reader;
StringStream s(kJson);
reader.Parse(s, writer);
fclose(fp);
fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
size_t size = (size_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
char* json = (char*)malloc(size + 1);
size_t readLength = fread(json, 1, size, fp);
json[readLength] = '\0';
fclose(fp);
remove(filename);
EXPECT_STREQ(kPrettyJson, json);
free(json);
}

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
@ -30,6 +24,7 @@ using namespace rapidjson;
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(float-equal)
#endif #endif
template<bool expect> template<bool expect>
@ -187,16 +182,20 @@ static void TestParseDouble() {
Reader reader; \ Reader reader; \
ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); \ ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); \
EXPECT_EQ(1u, h.step_); \ EXPECT_EQ(1u, h.step_); \
internal::Double e(x), a(h.actual_); \
if (fullPrecision) { \ if (fullPrecision) { \
EXPECT_EQ(x, h.actual_); \ EXPECT_EQ(e.Uint64Value(), a.Uint64Value()); \
if (x != h.actual_) \ if (e.Uint64Value() != a.Uint64Value()) \
printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \ printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \
} \ } \
else \ else { \
EXPECT_EQ(e.Sign(), a.Sign()); /* for 0.0 != -0.0 */ \
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, "1.0", 1.0); TEST_DOUBLE(fullPrecision, "1.0", 1.0);
TEST_DOUBLE(fullPrecision, "-1.0", -1.0); TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
TEST_DOUBLE(fullPrecision, "1.5", 1.5); TEST_DOUBLE(fullPrecision, "1.5", 1.5);
@ -220,13 +219,19 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double
TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double
TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0); TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313
TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0);
TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent
TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0);
TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0);
TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form
// Since // Since
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324 // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
@ -249,6 +254,32 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203124", 1.0); // previous double TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203124", 1.0); // previous double
TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203126", 1.00000000000000022); // next double TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203126", 1.00000000000000022); // next double
// Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc
TEST_DOUBLE(fullPrecision, "72057594037927928.0", 72057594037927928.0);
TEST_DOUBLE(fullPrecision, "72057594037927936.0", 72057594037927936.0);
TEST_DOUBLE(fullPrecision, "72057594037927932.0", 72057594037927936.0);
TEST_DOUBLE(fullPrecision, "7205759403792793199999e-5", 72057594037927928.0);
TEST_DOUBLE(fullPrecision, "7205759403792793200001e-5", 72057594037927936.0);
TEST_DOUBLE(fullPrecision, "9223372036854774784.0", 9223372036854774784.0);
TEST_DOUBLE(fullPrecision, "9223372036854775808.0", 9223372036854775808.0);
TEST_DOUBLE(fullPrecision, "9223372036854775296.0", 9223372036854775808.0);
TEST_DOUBLE(fullPrecision, "922337203685477529599999e-5", 9223372036854774784.0);
TEST_DOUBLE(fullPrecision, "922337203685477529600001e-5", 9223372036854775808.0);
TEST_DOUBLE(fullPrecision, "10141204801825834086073718800384", 10141204801825834086073718800384.0);
TEST_DOUBLE(fullPrecision, "10141204801825835211973625643008", 10141204801825835211973625643008.0);
TEST_DOUBLE(fullPrecision, "10141204801825834649023672221696", 10141204801825835211973625643008.0);
TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169599999e-5", 10141204801825834086073718800384.0);
TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169600001e-5", 10141204801825835211973625643008.0);
TEST_DOUBLE(fullPrecision, "5708990770823838890407843763683279797179383808", 5708990770823838890407843763683279797179383808.0);
TEST_DOUBLE(fullPrecision, "5708990770823839524233143877797980545530986496", 5708990770823839524233143877797980545530986496.0);
TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152", 5708990770823839524233143877797980545530986496.0);
TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185151999e-3", 5708990770823838890407843763683279797179383808.0);
TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152001e-3", 5708990770823839524233143877797980545530986496.0);
{ {
char n1e308[310]; // '1' followed by 308 '0' char n1e308[310]; // '1' followed by 308 '0'
n1e308[0] = '1'; n1e308[0] = '1';
@ -258,28 +289,53 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, n1e308, 1E308); TEST_DOUBLE(fullPrecision, n1e308, 1E308);
} }
#if 0 // Very slow // Cover trimming
static const unsigned count = 10000000; TEST_DOUBLE(fullPrecision,
// Random test for double "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
"6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505"
"1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621"
"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
"e-308",
2.2250738585072014e-308);
{ {
static const unsigned count = 100; // Tested with 1000000 locally
Random r; Random r;
Reader reader; // Reusing reader to prevent heap allocation
for (unsigned i = 0; i < count; i++) { // Exhaustively test different exponents with random significant
internal::Double d; for (uint64_t exp = 0; exp < 2047; exp++) {
do { ;
for (unsigned i = 0; i < count; i++) {
// Need to call r() in two statements for cross-platform coherent sequence. // Need to call r() in two statements for cross-platform coherent sequence.
uint64_t u = uint64_t(r()) << 32; uint64_t u = (exp << 52) | uint64_t(r() & 0x000FFFFF) << 32;
u |= uint64_t(r()); u |= uint64_t(r());
d = internal::Double(u); internal::Double d = internal::Double(u);
} while (d.IsNan() || d.IsInf()/* || !d.IsNormal()*/); // Also work for subnormal now
char buffer[32]; char buffer[32];
*internal::dtoa(d.Value(), buffer) = '\0'; *internal::dtoa(d.Value(), buffer) = '\0';
TEST_DOUBLE(fullPrecision, buffer, d.Value());
StringStream s(buffer);
ParseDoubleHandler h;
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: %sn Actual: %.17gnExpected: %.17gn", buffer, h.actual_, d.Value());
}
else {
EXPECT_EQ(d.Sign(), a.Sign()); /* for 0.0 != -0.0 */
EXPECT_DOUBLE_EQ(d.Value(), h.actual_);
}
}
} }
} }
#endif
#undef TEST_DOUBLE #undef TEST_DOUBLE
} }
@ -482,6 +538,17 @@ TEST(Reader, ParseString_Transcoding) {
EXPECT_EQ(StrLen(e), h.length_); EXPECT_EQ(StrLen(e), h.length_);
} }
TEST(Reader, ParseString_TranscodingWithValidation) {
const char* x = "\"Hello\"";
const wchar_t* e = L"Hello";
GenericStringStream<UTF8<> > is(x);
GenericReader<UTF8<>, UTF16<> > reader;
ParseStringHandler<UTF16<> > h;
reader.Parse<kParseValidateEncodingFlag>(is, h);
EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
EXPECT_EQ(StrLen(e), h.length_);
}
TEST(Reader, ParseString_NonDestructive) { TEST(Reader, ParseString_NonDestructive) {
StringStream s("\"Hello\\nWorld\""); StringStream s("\"Hello\\nWorld\"");
ParseStringHandler<UTF8<> > h; ParseStringHandler<UTF8<> > h;
@ -491,24 +558,31 @@ TEST(Reader, ParseString_NonDestructive) {
EXPECT_EQ(11u, h.length_); EXPECT_EQ(11u, h.length_);
} }
ParseErrorCode TestString(const char* str) { template <typename Encoding>
StringStream s(str); ParseErrorCode TestString(const typename Encoding::Ch* str) {
BaseReaderHandler<> h; GenericStringStream<Encoding> s(str);
Reader reader; BaseReaderHandler<Encoding> h;
reader.Parse<kParseValidateEncodingFlag>(s, h); GenericReader<Encoding, Encoding> reader;
reader.template Parse<kParseValidateEncodingFlag>(s, h);
return reader.GetParseErrorCode(); return reader.GetParseErrorCode();
} }
TEST(Reader, ParseString_Error) { TEST(Reader, ParseString_Error) {
#define TEST_STRING_ERROR(errorCode, str)\ #define TEST_STRING_ERROR(errorCode, str)\
EXPECT_EQ(errorCode, TestString(str)) EXPECT_EQ(errorCode, TestString<UTF8<> >(str))
#define ARRAY(...) { __VA_ARGS__ } #define ARRAY(...) { __VA_ARGS__ }
#define TEST_STRINGENCODING_ERROR(Encoding, utype, array) \ #define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
{ \ { \
static const utype ue[] = array; \ static const utype ue[] = array; \
static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\ EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\
/* decode error */\
GenericStringStream<Encoding> s(e);\
BaseReaderHandler<TargetEncoding> h;\
GenericReader<Encoding, TargetEncoding> reader;\
reader.Parse(s, h);\
EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode());\
} }
// Invalid escape character in string. // Invalid escape character in string.
@ -517,6 +591,10 @@ TEST(Reader, ParseString_Error) {
// Incorrect hex digit after \\u escape in string. // Incorrect hex digit after \\u escape in string.
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]");
// Quotation in \\u escape in string (Issue #288)
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]");
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]");
// The surrogate pair in string is invalid. // The surrogate pair in string is invalid.
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]");
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]");
@ -533,7 +611,7 @@ TEST(Reader, ParseString_Error) {
char e[] = { '[', '\"', 0, '\"', ']', '\0' }; char e[] = { '[', '\"', 0, '\"', ']', '\0' };
for (unsigned char c = 0x80u; c <= 0xBFu; c++) { for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
e[2] = c; e[2] = c;
ParseErrorCode error = TestString(e); ParseErrorCode error = TestString<UTF8<> >(e);
EXPECT_EQ(kParseErrorStringInvalidEncoding, error); EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
if (error != kParseErrorStringInvalidEncoding) if (error != kParseErrorStringInvalidEncoding)
std::cout << (unsigned)(unsigned char)c << std::endl; std::cout << (unsigned)(unsigned char)c << std::endl;
@ -552,30 +630,40 @@ TEST(Reader, ParseString_Error) {
// 4 Overlong sequences // 4 Overlong sequences
// 4.1 Examples of an overlong ASCII character // 4.1 Examples of an overlong ASCII character
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
// 4.2 Maximum overlong sequences // 4.2 Maximum overlong sequences
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
// 4.3 Overlong representation of the NUL character // 4.3 Overlong representation of the NUL character
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
// 5 Illegal code positions // 5 Illegal code positions
// 5.1 Single UTF-16 surrogates // 5.1 Single UTF-16 surrogates
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0'));
// Malform UTF-16 sequences
TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0'));
// Malform UTF-32 sequence
TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x110000, '\"', ']', '\0'));
// Malform ASCII sequence
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80), '\"', ']', '\0'));
#undef ARRAY #undef ARRAY
#undef TEST_STRINGARRAY_ERROR #undef TEST_STRINGARRAY_ERROR
@ -655,7 +743,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
} }
} }
bool Uint(unsigned i) { return Int(i); } bool Uint(unsigned i) { return Int(i); }
bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
bool String(const char* str, size_t, bool) { bool String(const char* str, size_t, bool) {
switch(step_) { switch(step_) {
case 1: EXPECT_STREQ("hello", str); step_++; return true; case 1: EXPECT_STREQ("hello", str); step_++; return true;
@ -965,6 +1053,17 @@ TEST(Reader, IterativeParsing_ErrorHandling) {
TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u);
TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u); TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u);
TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u);
TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 5u);
// Any JSON value can be a valid root element in RFC7159.
TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 2u);
TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u);
TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u);
TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u);
TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u);
TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u);
TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u);
TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u);
} }
template<typename Encoding = UTF8<> > template<typename Encoding = UTF8<> >
@ -1168,6 +1267,59 @@ TEST(Reader, IterativeParsing_ShortCircuit) {
} }
} }
// For covering BaseReaderHandler default functions
TEST(Reader, BaseReaderHandler_Default) {
BaseReaderHandler<> h;
Reader reader;
StringStream is("[null, true, -1, 1, -1234567890123456789, 1234567890123456789, 3.14, \"s\", { \"a\" : 1 }]");
EXPECT_TRUE(reader.Parse(is, h));
}
template <int e>
struct TerminateHandler {
bool Null() { return e != 0; }
bool Bool(bool) { return e != 1; }
bool Int(int) { return e != 2; }
bool Uint(unsigned) { return e != 3; }
bool Int64(int64_t) { return e != 4; }
bool Uint64(uint64_t) { return e != 5; }
bool Double(double) { return e != 6; }
bool String(const char*, SizeType, bool) { return e != 7; }
bool StartObject() { return e != 8; }
bool Key(const char*, SizeType, bool) { return e != 9; }
bool EndObject(SizeType) { return e != 10; }
bool StartArray() { return e != 11; }
bool EndArray(SizeType) { return e != 12; }
};
#define TEST_TERMINATION(e, json)\
{\
Reader reader;\
TerminateHandler<e> h;\
StringStream is(json);\
EXPECT_FALSE(reader.Parse(is, h));\
EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\
}
TEST(Reader, ParseTerminationByHandler) {
TEST_TERMINATION(0, "[null");
TEST_TERMINATION(1, "[true");
TEST_TERMINATION(1, "[false");
TEST_TERMINATION(2, "[-1");
TEST_TERMINATION(3, "[1");
TEST_TERMINATION(4, "[-1234567890123456789");
TEST_TERMINATION(5, "[1234567890123456789");
TEST_TERMINATION(6, "[0.5]");
TEST_TERMINATION(7, "[\"a\"");
TEST_TERMINATION(8, "[{");
TEST_TERMINATION(9, "[{\"a\"");
TEST_TERMINATION(10, "[{}");
TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object
TEST_TERMINATION(11, "{\"a\":[");
TEST_TERMINATION(12, "{\"a\":[]");
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
}
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif

View File

@ -0,0 +1,68 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2
// The unit tests prefix with SIMD should be skipped by Valgrind test
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
#endif
#define RAPIDJSON_NAMESPACE rapidjson_simd
#include "unittest.h"
#include "rapidjson/reader.h"
using namespace rapidjson_simd;
#ifdef RAPIDJSON_SSE2
#define SIMD_SUFFIX(name) name##_SSE2
#elif defined(RAPIDJSON_SSE42)
#define SIMD_SUFFIX(name) name##_SSE42
#else
#define SIMD_SUFFIX(name) name
#endif
template <typename StreamType>
void TestSkipWhitespace() {
for (int step = 1; step < 32; step++) {
char buffer[1025];
for (size_t i = 0; i < 1024; i++)
buffer[i] = " \t\r\n"[i % 4];
for (size_t i = 0; i < 1024; i += step)
buffer[i] = 'X';
buffer[1024] = '\0';
StreamType s(buffer);
size_t i = 0;
for (;;) {
SkipWhitespace(s);
if (s.Peek() == '\0')
break;
EXPECT_EQ(i, s.Tell());
EXPECT_EQ('X', s.Take());
i += step;
}
}
}
TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
TestSkipWhitespace<StringStream>();
TestSkipWhitespace<InsituStringStream>();
}

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
@ -54,6 +48,10 @@ TEST(StringBuffer, Push) {
buffer.Push(5); buffer.Push(5);
EXPECT_EQ(5u, buffer.GetSize()); EXPECT_EQ(5u, buffer.GetSize());
// Causes sudden expansion to make the stack's capacity equal to size
buffer.Push(65536u);
EXPECT_EQ(5u + 65536u, buffer.GetSize());
} }
TEST(StringBuffer, Pop) { TEST(StringBuffer, Pop) {

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"

View File

@ -1,28 +1,25 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/rapidjson.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
#if _MSC_VER #if _MSC_VER
_CrtMemState memoryState = { 0 }; _CrtMemState memoryState = { 0 };
_CrtMemCheckpoint(&memoryState); _CrtMemCheckpoint(&memoryState);

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef UNITTEST_H_ #ifndef UNITTEST_H_
#define UNITTEST_H_ #define UNITTEST_H_

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/document.h" #include "rapidjson/document.h"
@ -203,12 +197,28 @@ TEST(Value, EqualtoOperator) {
EXPECT_TRUE(z.RemoveMember("t")); EXPECT_TRUE(z.RemoveMember("t"));
TestUnequal(x, z); TestUnequal(x, z);
TestEqual(y, z); TestEqual(y, z);
y.AddMember("t", true, crtAllocator); y.AddMember("t", false, crtAllocator);
z.AddMember("t", true, z.GetAllocator()); z.AddMember("t", false, z.GetAllocator());
TestUnequal(x, y);
TestUnequal(z, x);
y["t"] = true;
z["t"] = true;
TestEqual(x, y); TestEqual(x, y);
TestEqual(y, z); TestEqual(y, z);
TestEqual(z, x); TestEqual(z, x);
// Swapping element order is not OK
x["a"][0].Swap(x["a"][1]);
TestUnequal(x, y);
x["a"][0].Swap(x["a"][1]);
TestEqual(x, y);
// Array of different size
x["a"].PushBack(4, allocator);
TestUnequal(x, y);
x["a"].PopBack();
TestEqual(x, y);
// Issue #129: compare Uint64 // Issue #129: compare Uint64
x.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0)); x.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0));
y.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)); y.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF));
@ -229,6 +239,13 @@ void TestCopyFrom() {
EXPECT_STREQ(v1.GetString(), v2.GetString()); EXPECT_STREQ(v1.GetString(), v2.GetString());
EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied
v1.SetString("bar", a); // copy string
v2.CopyFrom(v1, a);
EXPECT_TRUE(v1.GetType() == v2.GetType());
EXPECT_STREQ(v1.GetString(), v2.GetString());
EXPECT_NE(v1.GetString(), v2.GetString()); // string copied
v1.SetArray().PushBack(1234, a); v1.SetArray().PushBack(1234, a);
v2.CopyFrom(v1, a); v2.CopyFrom(v1, a);
EXPECT_TRUE(v2.IsArray()); EXPECT_TRUE(v2.IsArray());
@ -339,7 +356,7 @@ TEST(Value, Int) {
EXPECT_EQ(1234u, x.GetUint()); EXPECT_EQ(1234u, x.GetUint());
EXPECT_EQ(1234, x.GetInt64()); EXPECT_EQ(1234, x.GetInt64());
EXPECT_EQ(1234u, x.GetUint64()); EXPECT_EQ(1234u, x.GetUint64());
EXPECT_EQ(1234, x.GetDouble()); EXPECT_NEAR(1234.0, x.GetDouble(), 0.0);
//EXPECT_EQ(1234, (int)x); //EXPECT_EQ(1234, (int)x);
//EXPECT_EQ(1234, (unsigned)x); //EXPECT_EQ(1234, (unsigned)x);
//EXPECT_EQ(1234, (int64_t)x); //EXPECT_EQ(1234, (int64_t)x);
@ -397,7 +414,7 @@ TEST(Value, Uint) {
EXPECT_TRUE(x.IsUint()); EXPECT_TRUE(x.IsUint());
EXPECT_TRUE(x.IsInt64()); EXPECT_TRUE(x.IsInt64());
EXPECT_TRUE(x.IsUint64()); EXPECT_TRUE(x.IsUint64());
EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble(). EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); // Number can always be cast as double but !IsDouble().
EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsDouble());
EXPECT_FALSE(x.IsNull()); EXPECT_FALSE(x.IsNull());
@ -462,10 +479,19 @@ TEST(Value, Int64) {
z.SetInt64(2147483648LL); // 2^31, cannot cast as int z.SetInt64(2147483648LL); // 2^31, cannot cast as int
EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsInt());
EXPECT_TRUE(z.IsUint()); EXPECT_TRUE(z.IsUint());
EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0);
z.SetInt64(4294967296LL); // 2^32, cannot cast as uint z.SetInt64(4294967296LL); // 2^32, cannot cast as uint
EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsInt());
EXPECT_FALSE(z.IsUint()); EXPECT_FALSE(z.IsUint());
EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0);
z.SetInt64(-2147483649LL); // -2^31-1, cannot cast as int
EXPECT_FALSE(z.IsInt());
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
z.SetInt64(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)));
EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble());
} }
TEST(Value, Uint64) { TEST(Value, Uint64) {
@ -508,16 +534,15 @@ TEST(Value, Uint64) {
z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64 z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64
EXPECT_FALSE(z.IsInt64()); EXPECT_FALSE(z.IsInt64());
EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); // Issue 48
// Issue 48 EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
EXPECT_EQ(9223372036854775808uLL, z.GetUint64());
} }
TEST(Value, Double) { TEST(Value, Double) {
// Constructor with double // Constructor with double
Value x(12.34); Value x(12.34);
EXPECT_EQ(kNumberType, x.GetType()); EXPECT_EQ(kNumberType, x.GetType());
EXPECT_EQ(12.34, x.GetDouble()); EXPECT_NEAR(12.34, x.GetDouble(), 0.0);
EXPECT_TRUE(x.IsNumber()); EXPECT_TRUE(x.IsNumber());
EXPECT_TRUE(x.IsDouble()); EXPECT_TRUE(x.IsDouble());
@ -533,10 +558,10 @@ TEST(Value, Double) {
// SetDouble() // SetDouble()
Value z; Value z;
z.SetDouble(12.34); z.SetDouble(12.34);
EXPECT_EQ(12.34, z.GetDouble()); EXPECT_NEAR(12.34, z.GetDouble(), 0.0);
z = 56.78; z = 56.78;
EXPECT_EQ(56.78, z.GetDouble()); EXPECT_NEAR(56.78, z.GetDouble(), 0.0);
} }
TEST(Value, String) { TEST(Value, String) {
@ -977,6 +1002,7 @@ TEST(Value, Object) {
EXPECT_STREQ("Banana", x["B"].GetString()); EXPECT_STREQ("Banana", x["B"].GetString());
EXPECT_STREQ("CherryD", x[C0D].GetString()); EXPECT_STREQ("CherryD", x[C0D].GetString());
EXPECT_STREQ("CherryD", x[othername].GetString()); EXPECT_STREQ("CherryD", x[othername].GetString());
EXPECT_THROW(x["nonexist"], AssertException);
// const operator[] // const operator[]
EXPECT_STREQ("Apple", y["A"].GetString()); EXPECT_STREQ("Apple", y["A"].GetString());
@ -1041,13 +1067,15 @@ TEST(Value, Object) {
EXPECT_FALSE(citr >= itr); EXPECT_FALSE(citr >= itr);
// RemoveMember() // RemoveMember()
x.RemoveMember("A"); EXPECT_TRUE(x.RemoveMember("A"));
EXPECT_FALSE(x.HasMember("A")); EXPECT_FALSE(x.HasMember("A"));
x.RemoveMember("B"); EXPECT_TRUE(x.RemoveMember("B"));
EXPECT_FALSE(x.HasMember("B")); EXPECT_FALSE(x.HasMember("B"));
x.RemoveMember(othername); EXPECT_FALSE(x.RemoveMember("nonexist"));
EXPECT_TRUE(x.RemoveMember(othername));
EXPECT_FALSE(x.HasMember(name)); EXPECT_FALSE(x.HasMember(name));
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd()); EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
@ -1237,3 +1265,46 @@ TEST(Value, AllocateShortString) {
TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string) TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string) TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
} }
template <int e>
struct TerminateHandler {
bool Null() { return e != 0; }
bool Bool(bool) { return e != 1; }
bool Int(int) { return e != 2; }
bool Uint(unsigned) { return e != 3; }
bool Int64(int64_t) { return e != 4; }
bool Uint64(uint64_t) { return e != 5; }
bool Double(double) { return e != 6; }
bool String(const char*, SizeType, bool) { return e != 7; }
bool StartObject() { return e != 8; }
bool Key(const char*, SizeType, bool) { return e != 9; }
bool EndObject(SizeType) { return e != 10; }
bool StartArray() { return e != 11; }
bool EndArray(SizeType) { return e != 12; }
};
#define TEST_TERMINATION(e, json)\
{\
Document d; \
EXPECT_FALSE(d.Parse(json).HasParseError()); \
Reader reader; \
TerminateHandler<e> h;\
EXPECT_FALSE(d.Accept(h));\
}
TEST(Value, AcceptTerminationByHandler) {
TEST_TERMINATION(0, "[null]");
TEST_TERMINATION(1, "[true]");
TEST_TERMINATION(1, "[false]");
TEST_TERMINATION(2, "[-1]");
TEST_TERMINATION(3, "[2147483648]");
TEST_TERMINATION(4, "[-1234567890123456789]");
TEST_TERMINATION(5, "[9223372036854775808]");
TEST_TERMINATION(6, "[0.5]");
TEST_TERMINATION(7, "[\"a\"]");
TEST_TERMINATION(8, "[{}]");
TEST_TERMINATION(9, "[{\"a\":1}]");
TEST_TERMINATION(10, "[{}]");
TEST_TERMINATION(11, "{\"a\":[]}");
TEST_TERMINATION(12, "{\"a\":[]}");
}

View File

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "unittest.h" #include "unittest.h"
@ -46,7 +40,7 @@ TEST(Writer, Compact) {
StringBuffer buffer; \ StringBuffer buffer; \
Writer<StringBuffer> writer(buffer); \ Writer<StringBuffer> writer(buffer); \
Reader reader; \ Reader reader; \
reader.Parse<0>(s, writer); \ reader.Parse<kParseFullPrecisionFlag>(s, writer); \
EXPECT_STREQ(json, buffer.GetString()); \ EXPECT_STREQ(json, buffer.GetString()); \
EXPECT_TRUE(writer.IsComplete()); \ EXPECT_TRUE(writer.IsComplete()); \
} }
@ -89,10 +83,27 @@ TEST(Writer, String) {
TEST_ROUNDTRIP("[\"Hello\"]"); TEST_ROUNDTRIP("[\"Hello\"]");
TEST_ROUNDTRIP("[\"Hello\\u0000World\"]"); TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]"); TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
#if RAPIDJSON_HAS_STDSTRING
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.String(std::string("Hello\n"));
EXPECT_STREQ("\"Hello\\n\"", buffer.GetString());
}
#endif
} }
TEST(Writer, Double) { TEST(Writer, Double) {
TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]"); TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]");
TEST_ROUNDTRIP("0.0");
TEST_ROUNDTRIP("-0.0"); // Issue #289
TEST_ROUNDTRIP("1e30");
TEST_ROUNDTRIP("1.0");
TEST_ROUNDTRIP("5e-324"); // Min subnormal positive double
TEST_ROUNDTRIP("2.225073858507201e-308"); // Max subnormal positive double
TEST_ROUNDTRIP("2.2250738585072014e-308"); // Min normal positive double
TEST_ROUNDTRIP("1.7976931348623157e308"); // Max double
} }
@ -152,7 +163,7 @@ private:
}; };
TEST(Writer, OStreamWrapper) { TEST(Writer, OStreamWrapper) {
StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"u64\": 1234567890123456789, \"i64\":-1234567890123456789 } ");
std::stringstream ss; std::stringstream ss;
OStreamWrapper os(ss); OStreamWrapper os(ss);
@ -163,7 +174,7 @@ TEST(Writer, OStreamWrapper) {
reader.Parse<0>(s, writer); reader.Parse<0>(s, writer);
std::string actual = ss.str(); std::string actual = ss.str();
EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str()); EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}", actual.c_str());
} }
TEST(Writer, AssertRootMayBeAnyValue) { TEST(Writer, AssertRootMayBeAnyValue) {
@ -306,3 +317,61 @@ TEST(Writer, RootValueIsComplete) {
T(writer.String("")); T(writer.String(""));
#undef T #undef T
} }
TEST(Writer, InvalidEncoding) {
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
{
GenericStringBuffer<UTF16<> > buffer;
Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
writer.StartArray();
EXPECT_FALSE(writer.String("\xfe"));
EXPECT_FALSE(writer.String("\xff"));
EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
writer.EndArray();
}
// Fail in encoding
{
StringBuffer buffer;
Writer<StringBuffer, UTF32<> > writer(buffer);
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
EXPECT_FALSE(writer.String(s));
}
// Fail in unicode escaping in ASCII output
{
StringBuffer buffer;
Writer<StringBuffer, UTF32<>, ASCII<> > writer(buffer);
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
EXPECT_FALSE(writer.String(s));
}
}
TEST(Writer, InvalidEventSequence) {
// {]
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
EXPECT_THROW(writer.EndArray(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// [}
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartArray();
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// { 1:
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
EXPECT_THROW(writer.Int(1), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
}