Merge branch 'master' into optimization
1
.gitignore
vendored
@ -20,3 +20,4 @@ Testing
|
||||
install_manifest.txt
|
||||
Doxyfile
|
||||
DartConfiguration.tcl
|
||||
*.nupkg
|
||||
|
79
CHANGELOG.md
Normal file
@ -0,0 +1,79 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.0.2] - 2015-05-14
|
||||
|
||||
### Added
|
||||
* Add Value::XXXMember(...) overloads for std::string (#335)
|
||||
|
||||
### Fixed
|
||||
* Include rapidjson.h for all internal/error headers.
|
||||
* Parsing some numbers incorrectly in full-precision mode (`kFullPrecisionParseFlag`) (#342)
|
||||
* Fix alignment of 64bit platforms (#328)
|
||||
* Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502573f1afd3341073dd24b12c3db20fbde4)
|
||||
|
||||
### Changed
|
||||
* CMakeLists for include as a thirdparty in projects (#334, #337)
|
||||
* Change Document::ParseStream() to use stack allocator for Reader (ffbe38614732af8e0b3abdc8b50071f386a4a685)
|
||||
|
||||
## [1.0.1] - 2015-04-25
|
||||
|
||||
### 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.2...HEAD
|
||||
[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2
|
||||
[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1
|
||||
[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0
|
@ -1,11 +1,11 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules)
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules)
|
||||
|
||||
PROJECT(RapidJSON CXX)
|
||||
|
||||
set(LIB_MAJOR_VERSION "0")
|
||||
set(LIB_MINOR_VERSION "12")
|
||||
set(LIB_PATCH_VERSION "0")
|
||||
set(LIB_MAJOR_VERSION "1")
|
||||
set(LIB_MINOR_VERSION "0")
|
||||
set(LIB_PATCH_VERSION "2")
|
||||
set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}")
|
||||
|
||||
# compile in release with debug info mode by default
|
||||
@ -17,6 +17,8 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON)
|
||||
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON)
|
||||
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON)
|
||||
option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
|
||||
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
|
||||
|
||||
option(RAPIDJSON_HAS_STDSTRING "" OFF)
|
||||
if(RAPIDJSON_HAS_STDSTRING)
|
||||
@ -24,9 +26,9 @@ if(RAPIDJSON_HAS_STDSTRING)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||
endif()
|
||||
@ -43,7 +45,7 @@ ELSEIF(WIN32)
|
||||
ENDIF()
|
||||
SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in")
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
if(RAPIDJSON_BUILD_DOC)
|
||||
add_subdirectory(doc)
|
||||
|
@ -1,20 +1,27 @@
|
||||
SET(GTEST_SEARCH_PATH
|
||||
|
||||
SET(GTEST_SEARCH_PATH
|
||||
"${GTEST_SOURCE_DIR}"
|
||||
"${CMAKE_SOURCE_DIR}/thirdparty/gtest")
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest")
|
||||
|
||||
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()
|
||||
|
||||
FIND_PATH(GTEST_SOURCE_DIR
|
||||
NAMES CMakeLists.txt src/gtest_main.cc
|
||||
PATHS ${GTEST_SEARCH_PATH})
|
||||
|
||||
|
||||
# Debian installs gtest include directory in /usr/include, thus need to look
|
||||
# for include directory separately from source directory.
|
||||
FIND_PATH(GTEST_INCLUDE_DIR
|
||||
NAMES gtest/gtest.h
|
||||
PATH_SUFFIXES include
|
||||
HINTS ${GTEST_SOURCE_DIR}
|
||||
PATHS ${GTEST_SEARCH_PATH})
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 0.12.{build}
|
||||
version: 1.0.2.{build}
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
|
@ -3,9 +3,9 @@ find_package(Doxygen)
|
||||
IF(NOT DOXYGEN_FOUND)
|
||||
MESSAGE(STATUS "No Doxygen found. Documentation won't be built")
|
||||
ELSE()
|
||||
file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/include/*)
|
||||
file(GLOB MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/doc/*.md)
|
||||
list(APPEND MARKDOWN_DOC ${CMAKE_SOURCE_DIR}/readme.md)
|
||||
file(GLOB SOURCES ${CMAKE_CURRENT_LIST_DIR}/../include/*)
|
||||
file(GLOB MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../doc/*.md)
|
||||
list(APPEND MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../readme.md)
|
||||
|
||||
CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
|
||||
CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
|
||||
@ -15,7 +15,7 @@ ELSE()
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html
|
||||
DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
|
||||
)
|
||||
|
||||
add_custom_target(doc ALL DEPENDS html)
|
||||
|
@ -769,6 +769,7 @@ INPUT = readme.md \
|
||||
include/ \
|
||||
doc/features.md \
|
||||
doc/tutorial.md \
|
||||
doc/pointer.md \
|
||||
doc/stream.md \
|
||||
doc/encoding.md \
|
||||
doc/dom.md \
|
||||
|
@ -764,18 +764,19 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ./readme.zh-cn.md \
|
||||
./include/rapidjson/rapidjson.h \
|
||||
./include/ \
|
||||
./doc/features.zh-cn.md \
|
||||
./doc/tutorial.zh-cn.md \
|
||||
./doc/stream.zh-cn.md \
|
||||
./doc/encoding.zh-cn.md \
|
||||
./doc/dom.zh-cn.md \
|
||||
./doc/sax.zh-cn.md \
|
||||
./doc/performance.zh-cn.md \
|
||||
./doc/internals.md \
|
||||
./doc/faq.zh-cn.md
|
||||
INPUT = readme.zh-cn.md \
|
||||
include/rapidjson/rapidjson.h \
|
||||
include/ \
|
||||
doc/features.zh-cn.md \
|
||||
doc/tutorial.zh-cn.md \
|
||||
doc/pointer.zh-cn.md \
|
||||
doc/stream.zh-cn.md \
|
||||
doc/encoding.zh-cn.md \
|
||||
doc/dom.zh-cn.md \
|
||||
doc/sax.zh-cn.md \
|
||||
doc/performance.zh-cn.md \
|
||||
doc/internals.md \
|
||||
doc/faq.zh-cn.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 98 KiB |
@ -115,6 +115,7 @@ Parse flags | Meaning
|
||||
`kParseIterativeFlag` | Iterative(constant complexity in terms of function call stack size) parsing.
|
||||
`kParseStopWhenDoneFlag` | After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate `kParseErrorDocumentRootNotSingular` error. Using this flag for parsing multiple JSONs in the same stream.
|
||||
`kParseFullPrecisionFlag` | Parse number in full precision (slower). If this flag is not set, the normal precision (faster) is used. Normal precision has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error.
|
||||
`kParseCommentsFlag` | Allow one-line `// ...` and multi-line `/* ... */` comments (relaxed JSON syntax).
|
||||
|
||||
By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time.
|
||||
|
||||
@ -124,7 +125,7 @@ And the `InputStream` is type of input stream.
|
||||
|
||||
## Parse Error {#ParseError}
|
||||
|
||||
When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffet()`.
|
||||
When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`.
|
||||
|
||||
Parse Error Code | Description
|
||||
--------------------------------------------|---------------------------------------------------
|
||||
@ -159,8 +160,8 @@ Here shows an example of parse error handling.
|
||||
Document d;
|
||||
if (d.Parse(json).HasParseError()) {
|
||||
fprintf(stderr, "\nError(offset %u): %s\n",
|
||||
(unsigned)reader.GetErrorOffset(),
|
||||
GetParseError_En(reader.GetParseErrorCode()));
|
||||
(unsigned)d.GetErrorOffset(),
|
||||
GetParseError_En(d.GetParseErrorCode()));
|
||||
// ...
|
||||
}
|
||||
~~~~~~~~~~
|
||||
|
@ -115,6 +115,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
|
||||
`kParseIterativeFlag` | 迭代式(调用堆栈大小为常数复杂度)解析。
|
||||
`kParseStopWhenDoneFlag` | 当从流解析了一个完整的JSON根节点之后,停止继续处理余下的流。当使用了此标志,解析器便不会产生`kParseErrorDocumentRootNotSingular`错误。可使用本标志去解析同一个流里的多个JSON。
|
||||
`kParseFullPrecisionFlag` | 使用完整的精确度去解析数字(较慢)。如不设置此标节,则会使用正常的精确度(较快)。正常精确度会有最多3个[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place)的误差。
|
||||
`kParseCommentsFlag` | 容许单行 `// ...` 及多行 `/* ... */` 注释(放宽的JSON语法)。
|
||||
|
||||
由于使用了非类型模板参数,而不是函数参数,C++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。
|
||||
|
||||
@ -124,7 +125,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
|
||||
|
||||
## 解析错误 {#ParseError}
|
||||
|
||||
当解析过程顺利完成,`Document`便会含有解析结果。当过程出现错误,原来的DOM会*维持不便*。可使用`bool HasParseError()`、`ParseErrorCode GetParseError()`及`size_t GetParseOffet()`获取解析的错误状态。
|
||||
当解析过程顺利完成,`Document`便会含有解析结果。当过程出现错误,原来的DOM会*维持不便*。可使用`bool HasParseError()`、`ParseErrorCode GetParseError()`及`size_t GetParseOffset()`获取解析的错误状态。
|
||||
|
||||
解析错误代号 | 描述
|
||||
--------------------------------------------|---------------------------------------------------
|
||||
@ -159,8 +160,8 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
|
||||
Document d;
|
||||
if (d.Parse(json).HasParseError()) {
|
||||
fprintf(stderr, "\nError(offset %u): %s\n",
|
||||
(unsigned)reader.GetErrorOffset(),
|
||||
GetParseError_En(reader.GetParseErrorCode()));
|
||||
(unsigned)d.GetErrorOffset(),
|
||||
GetParseError_En(d.GetParseErrorCode()));
|
||||
// ...
|
||||
}
|
||||
~~~~~~~~~~
|
||||
|
60
doc/faq.md
@ -28,7 +28,7 @@
|
||||
|
||||
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?
|
||||
|
||||
@ -102,6 +102,64 @@
|
||||
|
||||
Some applications use 64-bit unsigned/signed integers. And these integers cannot be converted into `double` without loss of precision. So the parsers detects whether a JSON number is convertible to different types of integers and/or `double`.
|
||||
|
||||
8. How to clear-and-minimize a document or value?
|
||||
|
||||
Call one of the `SetXXX()` methods - they call destructor which deallocates DOM data:
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
Document d;
|
||||
...
|
||||
d.SetObject(); // clear and minimize
|
||||
~~~~~~~~~~
|
||||
|
||||
Alternatively, use equivalent of the [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize):
|
||||
~~~~~~~~~~cpp
|
||||
Value(kObjectType).Swap(d);
|
||||
~~~~~~~~~~
|
||||
or equivalent, but sightly longer to type:
|
||||
~~~~~~~~~~cpp
|
||||
d.Swap(Value(kObjectType).Move());
|
||||
~~~~~~~~~~
|
||||
|
||||
9. How to insert a document node into another document?
|
||||
|
||||
Let's take the following two DOM trees represented as JSON documents:
|
||||
~~~~~~~~~~cpp
|
||||
Document person;
|
||||
person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
|
||||
|
||||
Document address;
|
||||
address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}");
|
||||
~~~~~~~~~~
|
||||
Let's assume we want to merge them in such way that the whole `address` document becomes a node of the `person`:
|
||||
~~~~~~~~~~js
|
||||
{ "person": {
|
||||
"name": { "first": "Adam", "last": "Thomas" },
|
||||
"address": { "city": "Moscow", "street": "Quiet" }
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~
|
||||
|
||||
The most important requirement to take care of document and value life-cycle as well as consistent memory managent using the right allocator during the value transfer.
|
||||
|
||||
Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value:
|
||||
~~~~~~~~~~cpp
|
||||
Documnet address(person.GetAllocator());
|
||||
...
|
||||
person["person"].AddMember("address", address["address"], person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
Alternatively, if we don't want to explicitly refer to the root value of `address` by name, we can refer to it via iterator:
|
||||
~~~~~~~~~~cpp
|
||||
auto addressRoot = address.MemberBegin();
|
||||
person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
|
||||
Second way is to deep-clone the value from the address document:
|
||||
~~~~~~~~~~cpp
|
||||
Value addressValue = Value(address["address"], person.GetAllocator());
|
||||
person["person"].AddMember("address", addressValue, person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
|
||||
## Document/Value (DOM)
|
||||
|
||||
1. What is move semantics? Why?
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
6. 怎样安装RapidJSON?
|
||||
|
||||
见[安装一节](readme.zh-cn.md)。
|
||||
见[安装一节](../readme.zh-cn.md#安装)。
|
||||
|
||||
7. RapidJSON能否运行于我的平台?
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
|
||||
12. 有没有其他替代品?
|
||||
|
||||
有许多替代品。例如nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)列出了一些开源的C/C++ JSON库。[json.org](http://www.json.org/)也有一个列表。
|
||||
有许多替代品。例如[nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)列出了一些开源的C/C++ JSON库。[json.org](http://www.json.org/)也有一个列表。
|
||||
|
||||
## JSON
|
||||
|
||||
@ -98,10 +98,69 @@
|
||||
|
||||
错误信息存储在`ParseResult`,它包含错误代号及偏移值(从JSON开始至错误处的字符数目)。可以把错误代号翻译为人类可读的错误讯息。
|
||||
|
||||
7. 为可不只使用`double`去表示JSON number?
|
||||
7. 为何不只使用`double`去表示JSON number?
|
||||
|
||||
一些应用需要使用64位无号/有号整数。这些整数不能无损地转换成`double`。因此解析器会检测一个JSON number是否能转换至各种整数类型及`double`。
|
||||
|
||||
8. 如何清空并最小化`document`或`value`的容量?
|
||||
|
||||
调用 `SetXXX()` 方法 - 这些方法会调用析构函数,并重建空的Object或Array:
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
Document d;
|
||||
...
|
||||
d.SetObject(); // clear and minimize
|
||||
~~~~~~~~~~
|
||||
|
||||
另外,也可以参考在 [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize)中的一种等价的方法:
|
||||
~~~~~~~~~~cpp
|
||||
Value(kObjectType).Swap(d);
|
||||
~~~~~~~~~~
|
||||
或者,使用这个稍微长一点的代码也能完成同样的事情:
|
||||
~~~~~~~~~~cpp
|
||||
d.Swap(Value(kObjectType).Move());
|
||||
~~~~~~~~~~
|
||||
|
||||
9. 如何将一个`document`节点插入到另一个`document`中?
|
||||
|
||||
比如有以下两个document(DOM):
|
||||
~~~~~~~~~~cpp
|
||||
Document person;
|
||||
person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
|
||||
|
||||
Document address;
|
||||
address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}");
|
||||
~~~~~~~~~~
|
||||
假设我们希望将整个 `address` 插入到`person`中,作为其的一个子节点:
|
||||
~~~~~~~~~~js
|
||||
{ "person": {
|
||||
"name": { "first": "Adam", "last": "Thomas" },
|
||||
"address": { "city": "Moscow", "street": "Quiet" }
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~
|
||||
|
||||
在插入节点的过程中需要注意`document`和`value`的生命周期并且正确地使用allocator进行内存分配和管理。
|
||||
|
||||
一个简单有效的方法就是修改上述`address`变量的定义,让其使用`person`的allocator初始化,然后将其添加到根节点。
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
Documnet address(person.GetAllocator());
|
||||
...
|
||||
person["person"].AddMember("address", address["address"], person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
当然,如果你不想通过显式地写出`address`的key来得到其值,可以使用迭代器来实现:
|
||||
~~~~~~~~~~cpp
|
||||
auto addressRoot = address.MemberBegin();
|
||||
person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
|
||||
此外,还可以通过深拷贝address document来实现:
|
||||
~~~~~~~~~~cpp
|
||||
Value addressValue = Value(address["address"], person.GetAllocator());
|
||||
person["person"].AddMember("address", addressValue, person.GetAllocator());
|
||||
~~~~~~~~~~
|
||||
|
||||
## Document/Value (DOM)
|
||||
|
||||
1. 什么是转移语意?为什么?
|
||||
|
@ -23,6 +23,8 @@
|
||||
* Support Unicode surrogate.
|
||||
* Support null character (`"\u0000"`)
|
||||
* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
|
||||
* Support optional relaxed syntax.
|
||||
* Single line (`// ...`) and multiple line (`/* ... */`) comments.
|
||||
|
||||
## Unicode
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
* 支持Unicod代理对(surrogate pair)。
|
||||
* 支持空字符(`"\u0000"`)。
|
||||
* 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。
|
||||
* 支持放宽的可选语法
|
||||
* 单行(`// ...`)及多行(`/* ... */`) 注释。
|
||||
|
||||
## Unicode
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
(document.getElementsByClassName('contents')[0]).appendChild(dt);
|
||||
|
||||
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);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -16,6 +16,15 @@ $mathjax
|
||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||
$extrastylesheet
|
||||
</head>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-63929386-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
|
||||
|
234
doc/pointer.md
Normal file
@ -0,0 +1,234 @@
|
||||
# Pointer
|
||||
|
||||
## Status: experimental, shall be included in v1.1
|
||||
|
||||
JSON Pointer is a standardized ([RFC6901]) way to select a value inside a JSON Document (DOM). This can be analogous to XPath for XML document. However, JSON Pointer is much simpler, and a single JSON Pointer only pointed to a single value.
|
||||
|
||||
Using RapidJSON's implementation of JSON Pointer can simplify some manipulations of the DOM.
|
||||
|
||||
[TOC]
|
||||
|
||||
# JSON Pointer {#JsonPointer}
|
||||
|
||||
A JSON Pointer is a list of zero-to-many tokens, each prefixed by `/`. Each token can be a string or a number. For example, given a JSON:
|
||||
~~~javascript
|
||||
{
|
||||
"foo" : ["bar", "baz"],
|
||||
"pi" : 3.1416
|
||||
}
|
||||
~~~
|
||||
|
||||
The following JSON Pointers resolve this JSON as:
|
||||
|
||||
1. `"/foo"` → `[ "bar", "baz" ]`
|
||||
2. `"/foo/0"` → `"bar"`
|
||||
3. `"/foo/1"` → `"baz"`
|
||||
4. `"/pi"` → `3.1416`
|
||||
|
||||
Note that, an empty JSON Pointer `""` (zero token) resolves to the whole JSON.
|
||||
|
||||
# Basic Usage {#BasicUsage}
|
||||
|
||||
The following example code is self-explanatory.
|
||||
|
||||
~~~cpp
|
||||
#include "rapidjson/pointer.h"
|
||||
|
||||
// ...
|
||||
Document d;
|
||||
|
||||
// Create DOM by Set()
|
||||
Pointer("/project").Set(d, "RapidJSON");
|
||||
Pointer("/stars").Set(d, 10);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 10 }
|
||||
|
||||
// Access DOM by Get(). It return nullptr if the value does not exist.
|
||||
if (Value* stars = Pointer("/stars").Get(d))
|
||||
stars->SetInt(stars->GetInt() + 1);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11 }
|
||||
|
||||
// Set() and Create() automatically generate parents if not exist.
|
||||
Pointer("/a/b/0").Create(d);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
|
||||
|
||||
// GetWithDefault() returns reference. And it deep clones the default value.
|
||||
Value& hello = Pointer("/hello").GetWithDefault(d, "world");
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" }
|
||||
|
||||
// Swap() is similar to Set()
|
||||
Value x("C++");
|
||||
Pointer("/hello").Swap(d, x);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
|
||||
// x becomes "world"
|
||||
|
||||
// Erase a member or element, return true if the value exists
|
||||
bool success = Pointer("/a").Erase(d);
|
||||
assert(success);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 10 }
|
||||
~~~
|
||||
|
||||
# Helper Functions {#HelperFunctions}
|
||||
|
||||
Since object-oriented calling convention may be non-intuitive, RapidJSON also provides helper functions, which just wrap the member functions with free-functions.
|
||||
|
||||
The following example does exactly the same as the above one.
|
||||
|
||||
~~~cpp
|
||||
Document d;
|
||||
|
||||
SetValueByPointer(d, "/project", "RapidJSON");
|
||||
SetValueByPointer(d, "/stars", 10);
|
||||
|
||||
if (Value* stars = GetValueByPointer(d, "/stars"))
|
||||
stars->SetInt(stars->GetInt() + 1);
|
||||
|
||||
CreateValueByPointer(d, "/a/b/0");
|
||||
|
||||
Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
|
||||
|
||||
Value x("C++");
|
||||
SwapValueByPointer(d, "/hello", x);
|
||||
|
||||
bool success = EraseValueByPointer(d, "/a");
|
||||
assert(success);
|
||||
~~~
|
||||
|
||||
The conventions are shown here for comparison:
|
||||
|
||||
1. `Pointer(source).<Method>(root, ...)`
|
||||
2. `<Method>ValueByPointer(root, Pointer(source), ...)`
|
||||
3. `<Method>ValueByPointer(root, source, ...)`
|
||||
|
||||
# Resolving Pointer {#ResolvingPointer}
|
||||
|
||||
`Pointer::Get()` or `GetValueByPointer()` function does not modify the DOM. If the tokens cannot match a value in the DOM, it returns `nullptr`. User can use this to check whether a value exists.
|
||||
|
||||
Note that, numerical tokens can represent an array index or member name. The resolving process will match the values according to the types of value.
|
||||
|
||||
~~~javascript
|
||||
{
|
||||
"0" : 123,
|
||||
"1" : [456]
|
||||
}
|
||||
~~~
|
||||
|
||||
1. `"/0"` → `123`
|
||||
2. `"/1/0"` → `456`
|
||||
|
||||
The token `"0"` is treated as member name in the first pointer. It is treated as an array index in the second pointer.
|
||||
|
||||
The other functions, including `Create()`, `GetWithDefault()`, `Set()` and `Swap()`, will change the DOM. These functions will always succeed. They will create the parent values if they do not exist. If the parent values do not match the tokens, they will also be forced to change their type. Changing the type also mean fully removal of that DOM subtree.
|
||||
|
||||
Parsing the above JSON into `d`,
|
||||
|
||||
~~~cpp
|
||||
SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } }
|
||||
~~~
|
||||
|
||||
## Resolving Minus Sign Token
|
||||
|
||||
Besides, [RFC6901] defines a special token `-` (single minus sign), which represents the pass-the-end element of an array. `Get()` only treats this token as a member name '"-"'. Yet the other functions can resolve this for array, equivalent to calling `Value::PushBack()` to the array.
|
||||
|
||||
~~~cpp
|
||||
Document d;
|
||||
d.Parse("{\"foo\":[123]}");
|
||||
SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] }
|
||||
SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 }
|
||||
~~~
|
||||
|
||||
## Resolving Document and Value
|
||||
|
||||
When using `p.Get(root)` or `GetValueByPointer(root, p)`, `root` is a (const) `Value&`. That means, it can be a subtree of the DOM.
|
||||
|
||||
The other functions have two groups of signature. One group uses `Document& document` as parameter, another one uses `Value& root`. The first group uses `document.GetAllocator()` for creating values. And the second group needs user to supply an allocator, like the functions in DOM.
|
||||
|
||||
All examples above do not require an allocator parameter, because the first parameter is a `Document&`. But if you want to resolve a pointer to a subtree, you need to supply the allocator as in the following example:
|
||||
|
||||
~~~cpp
|
||||
class Person {
|
||||
public:
|
||||
Person() {
|
||||
document_ = new Document();
|
||||
// CreateValueByPointer() here no need allocator
|
||||
SetLocation(CreateValueByPointer(*document_, "/residence"), ...);
|
||||
SetLocation(CreateValueByPointer(*document_, "/office"), ...);
|
||||
};
|
||||
|
||||
private:
|
||||
void SetLocation(Value& location, const char* country, const char* addresses[2]) {
|
||||
Value::Allocator& a = document_->GetAllocator();
|
||||
// SetValueByPointer() here need allocator
|
||||
SetValueByPointer(location, "/country", country, a);
|
||||
SetValueByPointer(location, "/address/0", address[0], a);
|
||||
SetValueByPointer(location, "/address/1", address[1], a);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
Document* document_;
|
||||
};
|
||||
~~~
|
||||
|
||||
`Erase()` or `EraseValueByPointer()` does not need allocator. And they return `true` if the value is erased successfully.
|
||||
|
||||
# Error Handling {#ErrorHandling}
|
||||
|
||||
A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns `false`. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information.
|
||||
|
||||
Note that, all resolving functions assumes valid pointer. Resolving with an invalid pointer causes assertion failure.
|
||||
|
||||
# URI Fragment Representation {#URIFragment}
|
||||
|
||||
In addition to the string representation of JSON pointer that we are using till now, [RFC6901] also defines the URI fragment representation of JSON pointer. URI fragment is specified in [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax".
|
||||
|
||||
The main differences are that a the URI fragment always has a `#` (pound sign) in the beginning, and some characters are encoded by percent-encoding in UTF-8 sequence. For example, the following table shows different C/C++ string literals of different representations.
|
||||
|
||||
String Representation | URI Fragment Representation | Pointer Tokens (UTF-8)
|
||||
----------------------|-----------------------------|------------------------
|
||||
`"/foo/0"` | `"#/foo/0"` | `{"foo", 0}`
|
||||
`"/a~1b"` | `"#/a~1b"` | `{"a/b"}`
|
||||
`"/m~0n"` | `"#/m~0n"` | `{"m~n"}`
|
||||
`"/ "` | `"#/%20"` | `{" "}`
|
||||
`"/\0"` | `"#/%00"` | `{"\0"}`
|
||||
`"/€"` | `"#/%E2%82%AC"` | `{"€"}`
|
||||
|
||||
RapidJSON fully support URI fragment representation. It automatically detects the pound sign during parsing.
|
||||
|
||||
# Stringify
|
||||
|
||||
You may also stringify a `Pointer` to a string or other output streams. This can be done by:
|
||||
|
||||
~~~
|
||||
Pointer p(...);
|
||||
StringBuffer sb;
|
||||
p.Stringify(sb);
|
||||
std::cout << sb.GetString() << std::endl;
|
||||
~~~
|
||||
|
||||
It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`.
|
||||
|
||||
# User-Supplied Tokens {#UserSuppliedTokens}
|
||||
|
||||
If a pointer will be resolved multiple times, it should be constructed once, and then apply it to different DOMs or in different times. This reduce time and memory allocation for constructing `Pointer` multiple times.
|
||||
|
||||
We can go one step further, to completely eliminate the parsing process and dynamic memory allocation, we can establish the token array directly:
|
||||
|
||||
~~~cpp
|
||||
#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
|
||||
#define INDEX(i) { #i, sizeof(#i) - 1, i }
|
||||
|
||||
static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
|
||||
static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
|
||||
// Equivalent to static const Pointer p("/foo/123");
|
||||
~~~
|
||||
|
||||
This may be useful for memory constrained systems.
|
||||
|
||||
[RFC3986]: https://tools.ietf.org/html/rfc3986
|
||||
[RFC6901]: https://tools.ietf.org/html/rfc6901
|
234
doc/pointer.zh-cn.md
Normal file
@ -0,0 +1,234 @@
|
||||
# Pointer
|
||||
|
||||
## 状态: 实验性,应该会合进 v1.1
|
||||
|
||||
JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 简单得多,而且每个 JSON Pointer 仅指向单个值。
|
||||
|
||||
使用 RapidJSON 的 JSON Pointer 实现能简化一些 DOM 的操作。
|
||||
|
||||
[TOC]
|
||||
|
||||
# JSON Pointer {#JsonPointer}
|
||||
|
||||
一个 JSON Pointer 由一串(零至多个)token 所组成,每个 token 都有 `/` 前缀。每个 token 可以是一个字符串或数字。例如,给定一个 JSON:
|
||||
~~~javascript
|
||||
{
|
||||
"foo" : ["bar", "baz"],
|
||||
"pi" : 3.1416
|
||||
}
|
||||
~~~
|
||||
|
||||
以下的 JSON Pointer 解析为:
|
||||
|
||||
1. `"/foo"` → `[ "bar", "baz" ]`
|
||||
2. `"/foo/0"` → `"bar"`
|
||||
3. `"/foo/1"` → `"baz"`
|
||||
4. `"/pi"` → `3.1416`
|
||||
|
||||
要注意,一个空 JSON Pointer `""` (零个token)解析为整个 JSON。
|
||||
|
||||
# 基本使用方法 {#BasicUsage}
|
||||
|
||||
以下的代码范例不解自明。
|
||||
|
||||
~~~cpp
|
||||
#include "rapidjson/pointer.h"
|
||||
|
||||
// ...
|
||||
Document d;
|
||||
|
||||
// 使用 Set() 创建 DOM
|
||||
Pointer("/project").Set(d, "RapidJSON");
|
||||
Pointer("/stars").Set(d, 10);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 10 }
|
||||
|
||||
// 使用 Get() 访问 DOM。若该值不存在则返回 nullptr。
|
||||
if (Value* stars = Pointer("/stars").Get(d))
|
||||
stars->SetInt(stars->GetInt() + 1);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11 }
|
||||
|
||||
// Set() 和 Create() 自动生成父值(如果它们不存在)。
|
||||
Pointer("/a/b/0").Create(d);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
|
||||
|
||||
// GetWithDefault() 返回引用。若该值不存在则会深拷贝缺省值。
|
||||
Value& hello = Pointer("/hello").GetWithDefault(d, "world");
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" }
|
||||
|
||||
// Swap() 和 Set() 相似
|
||||
Value x("C++");
|
||||
Pointer("/hello").Swap(d, x);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
|
||||
// x 变成 "world"
|
||||
|
||||
// 删去一个成员或元素,若值存在返回 true
|
||||
bool success = Pointer("/a").Erase(d);
|
||||
assert(success);
|
||||
|
||||
// { "project" : "RapidJSON", "stars" : 10 }
|
||||
~~~
|
||||
|
||||
# 辅助函数 {#HelperFunctions}
|
||||
|
||||
由于面向对象的调用习惯可能不符直觉,RapidJSON 也提供了一些辅助函数,它们把成员函数包装成自由函数。
|
||||
|
||||
以下的例子与上面例子所做的事情完全相同。
|
||||
|
||||
~~~cpp
|
||||
Document d;
|
||||
|
||||
SetValueByPointer(d, "/project", "RapidJSON");
|
||||
SetValueByPointer(d, "/stars", 10);
|
||||
|
||||
if (Value* stars = GetValueByPointer(d, "/stars"))
|
||||
stars->SetInt(stars->GetInt() + 1);
|
||||
|
||||
CreateValueByPointer(d, "/a/b/0");
|
||||
|
||||
Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
|
||||
|
||||
Value x("C++");
|
||||
SwapValueByPointer(d, "/hello", x);
|
||||
|
||||
bool success = EraseValueByPointer(d, "/a");
|
||||
assert(success);
|
||||
~~~
|
||||
|
||||
以下对比 3 种调用方式:
|
||||
|
||||
1. `Pointer(source).<Method>(root, ...)`
|
||||
2. `<Method>ValueByPointer(root, Pointer(source), ...)`
|
||||
3. `<Method>ValueByPointer(root, source, ...)`
|
||||
|
||||
# 解析 Pointer {#ResolvingPointer}
|
||||
|
||||
`Pointer::Get()` 或 `GetValueByPointer()` 函数并不修改 DOM。若那些 token 不能匹配 DOM 里的值,这些函数便返回 `nullptr`。使用者可利用这个方法来检查一个值是否存在。
|
||||
|
||||
注意,数值 token 可表示数组索引或成员名字。解析过程中会按值的类型来匹配。
|
||||
|
||||
~~~javascript
|
||||
{
|
||||
"0" : 123,
|
||||
"1" : [456]
|
||||
}
|
||||
~~~
|
||||
|
||||
1. `"/0"` → `123`
|
||||
2. `"/1/0"` → `456`
|
||||
|
||||
Token `"0"` 在第一个 pointer 中被当作成员名字。它在第二个 pointer 中被当作成数组索引。
|
||||
|
||||
其他函数会改变 DOM,包括`Create()`、`GetWithDefault()`、`Set()`、`Swap()`。这些函数总是成功的。若一些父值不存在,就会创建它们。若父值类型不匹配 token,也会强行改变其类型。改变类型也意味着完全移除其 DOM 子树的内容。
|
||||
|
||||
例如,把上面的 JSON 解译至 `d` 之后,
|
||||
|
||||
~~~cpp
|
||||
SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } }
|
||||
~~~
|
||||
|
||||
## 解析负号 token
|
||||
|
||||
另外,[RFC6901] 定义了一个特殊 token `-` (单个负号),用于表示数组最后元素的下一个元素。 `Get()` 只会把此 token 当作成员名字 '"-"'。而其他函数则会以此解析数组,等同于对数组调用 `Value::PushBack()` 。
|
||||
|
||||
~~~cpp
|
||||
Document d;
|
||||
d.Parse("{\"foo\":[123]}");
|
||||
SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] }
|
||||
SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 }
|
||||
~~~
|
||||
|
||||
## 解析 Document 及 Value
|
||||
|
||||
当使用 `p.Get(root)` 或 `GetValueByPointer(root, p)`,`root` 是一个(常数) `Value&`。这意味着,它也可以是 DOM 里的一个子树。
|
||||
|
||||
其他函数有两组签名。一组使用 `Document& document` 作为参数,另一组使用 `Value& root`。第一组使用 `document.GetAllocator()` 去创建值,而第二组则需要使用者提供一个 allocator,如同 DOM 里的函数。
|
||||
|
||||
以上例子都不需要 allocator 参数,因为它的第一个参数是 `Document&`。但如果你需要对一个子树进行解析,就需要如下面的例子般提供 allocator:
|
||||
|
||||
~~~cpp
|
||||
class Person {
|
||||
public:
|
||||
Person() {
|
||||
document_ = new Document();
|
||||
// CreateValueByPointer() here no need allocator
|
||||
SetLocation(CreateValueByPointer(*document_, "/residence"), ...);
|
||||
SetLocation(CreateValueByPointer(*document_, "/office"), ...);
|
||||
};
|
||||
|
||||
private:
|
||||
void SetLocation(Value& location, const char* country, const char* addresses[2]) {
|
||||
Value::Allocator& a = document_->GetAllocator();
|
||||
// SetValueByPointer() here need allocator
|
||||
SetValueByPointer(location, "/country", country, a);
|
||||
SetValueByPointer(location, "/address/0", address[0], a);
|
||||
SetValueByPointer(location, "/address/1", address[1], a);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
Document* document_;
|
||||
};
|
||||
~~~
|
||||
|
||||
`Erase()` 或 `EraseValueByPointer()` 不需要 allocator。而且它们成功删除值之后会返回 `true`。
|
||||
|
||||
# 错误处理 {#ErrorHandling}
|
||||
|
||||
`Pointer` 在其建构函数里会解译源字符串。若有解析错误,`Pointer::IsValid()` 返回 `false`。你可使用 `Pointer::GetParseErrorCode()` 和 `GetParseErrorOffset()` 去获取错信息。
|
||||
|
||||
要注意的是,所有解析函数都假设 pointer 是合法的。对一个非法 pointer 解析会做成断言失败。
|
||||
|
||||
# URI 片段表示方式 {#URIFragment}
|
||||
|
||||
除了我们一直在使用的字符串方式表示 JSON pointer,[RFC6901]也定义了一个 JSON Pointer 的 URI 片段(fragment)表示方式。URI 片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax"。
|
||||
|
||||
URI 片段的主要分别是必然以 `#` (pound sign)开头,而一些字符也会以百分比编码成 UTF-8 序列。例如,以下的表展示了不同表示法下的 C/C++ 字符串常数。
|
||||
|
||||
字符串表示方式 | URI 片段表示方式 | Pointer Tokens (UTF-8)
|
||||
----------------------|-----------------------------|------------------------
|
||||
`"/foo/0"` | `"#/foo/0"` | `{"foo", 0}`
|
||||
`"/a~1b"` | `"#/a~1b"` | `{"a/b"}`
|
||||
`"/m~0n"` | `"#/m~0n"` | `{"m~n"}`
|
||||
`"/ "` | `"#/%20"` | `{" "}`
|
||||
`"/\0"` | `"#/%00"` | `{"\0"}`
|
||||
`"/€"` | `"#/%E2%82%AC"` | `{"€"}`
|
||||
|
||||
RapidJSON 完全支持 URI 片段表示方式。它在解译时会自动检测 `#` 号。
|
||||
|
||||
# 字符串化
|
||||
|
||||
你也可以把一个 `Pointer` 字符串化,储存于字符串或其他输出流。例如:
|
||||
|
||||
~~~
|
||||
Pointer p(...);
|
||||
StringBuffer sb;
|
||||
p.Stringify(sb);
|
||||
std::cout << sb.GetString() << std::endl;
|
||||
~~~
|
||||
|
||||
使用 `StringifyUriFragment()` 可以把 pointer 字符串化为 URI 片段表示法。
|
||||
|
||||
# 使用者提供的 tokens {#UserSuppliedTokens}
|
||||
|
||||
若一个 pointer 会用于多次解析,它应该只被创建一次,然后再施于不同的 DOM ,或在不同时间做解析。这样可以避免多次创键 `Pointer`,节省时间和内存分配。
|
||||
|
||||
我们甚至可以再更进一步,完全消去解析过程及动态内存分配。我们可以直接生成 token 数组:
|
||||
|
||||
~~~cpp
|
||||
#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
|
||||
#define INDEX(i) { #i, sizeof(#i) - 1, i }
|
||||
|
||||
static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
|
||||
static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
|
||||
// Equivalent to static const Pointer p("/foo/123");
|
||||
~~~
|
||||
|
||||
这种做法可能适合内存受限的系统。
|
||||
|
||||
[RFC3986]: https://tools.ietf.org/html/rfc3986
|
||||
[RFC6901]: https://tools.ietf.org/html/rfc6901
|
@ -175,7 +175,7 @@ bool Parse(InputStream& is, Handler& handler);
|
||||
|
||||
# Writer {#Writer}
|
||||
|
||||
`Reader`把JSON转换(解析)成为事件。`Writer`完全做相反的事情。它把事件转换成JSON。
|
||||
`Reader`把JSON转换(解析)成为事件。`Writer`做完全相反的事情。它把事件转换成JSON。
|
||||
|
||||
`Writer`是非常容易使用的。若你的应用程序只需把一些数据转换成JSON,可能直接使用`Writer`,会比建立一个`Document`然后用`Writer`把它转换成JSON更加方便。
|
||||
|
||||
@ -265,7 +265,7 @@ public:
|
||||
|
||||
## PrettyWriter {#PrettyWriter}
|
||||
|
||||
`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但就适合人类阅读。
|
||||
`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但不适合人类阅读。
|
||||
|
||||
因此,RapidJSON提供了一个`PrettyWriter`,它在输出中加入缩进及换行。
|
||||
|
||||
@ -386,13 +386,13 @@ Error: Terminate parsing due to Handler error.
|
||||
at offset 59 near '} }...'
|
||||
~~~~~~~~~~
|
||||
|
||||
第一个JSON(`json1`)被成功地解析至`MessageMap`。由于`MessageMap`是一个`std::map`,列印次序按键值排序。此次序与JSON中的次序不同。
|
||||
第一个JSON(`json1`)被成功地解析至`MessageMap`。由于`MessageMap`是一个`std::map`,打印次序按键值排序。此次序与JSON中的次序不同。
|
||||
|
||||
在第二个JSON(`json2`)中,`foo`的值是一个空object。由于它是一个object,`MessageHandler::StartObject()`会被调用。然而,在`state_ = kExpectValue`的情况下,该函数会返回`false`,并令到解析过程终止。错误代码是`kParseErrorTermination`。
|
||||
在第二个JSON(`json2`)中,`foo`的值是一个空object。由于它是一个object,`MessageHandler::StartObject()`会被调用。然而,在`state_ = kExpectValue`的情况下,该函数会返回`false`,并导致解析过程终止。错误代码是`kParseErrorTermination`。
|
||||
|
||||
## 过滤JSON {#Filtering}
|
||||
|
||||
如前面提及过,`Writer`可处理`Reader`发出的事件。`condense`例子简单地设置`Writer`作为一个`Reader`的处理器,因此它能移除JSON中的所有空白字符。`pretty`例子使用同样的关系,只是以`PrettyWriter`取代`Writer`。因此`pretty`能够重新格式化JSON,加入缩进及换行。
|
||||
如前面提及过,`Writer`可处理`Reader`发出的事件。`example/condense/condense.cpp`例子简单地设置`Writer`作为一个`Reader`的处理器,因此它能移除JSON中的所有空白字符。`example/pretty/pretty.cpp`例子使用同样的关系,只是以`PrettyWriter`取代`Writer`。因此`pretty`能够重新格式化JSON,加入缩进及换行。
|
||||
|
||||
实际上,我们可以使用SAX风格API去加入(多个)中间层去过滤JSON的内容。例如`capitalize`例子可以把所有JSON string改为大写。
|
||||
|
||||
@ -472,5 +472,5 @@ int main(int, char*[]) {
|
||||
["HELLO\nWORLD"]
|
||||
~~~~~~~~~~
|
||||
|
||||
我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对些一些处理情况,用DOM会比SAX更容易实现。
|
||||
我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对于处理某些情况,用DOM会比SAX更容易实现。
|
||||
|
||||
|
@ -320,7 +320,7 @@ std::stringstream ss(json);
|
||||
IStreamWrapper is(ss);
|
||||
|
||||
Document d;
|
||||
d.Parse(is);
|
||||
d.ParseStream(is);
|
||||
~~~~~~~~~~
|
||||
|
||||
Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library.
|
||||
|
@ -320,7 +320,7 @@ std::stringstream ss(json);
|
||||
IStreamWrapper is(ss);
|
||||
|
||||
Document d;
|
||||
d.Parse(is);
|
||||
d.ParseStream(is);
|
||||
~~~~~~~~~~
|
||||
|
||||
但要注意,由于标准库的内部开销问,此实现的性能可能不如RapidJSON的内存/文件流。
|
||||
|
@ -192,7 +192,7 @@ Checking | Obtaining
|
||||
`bool IsNumber()` | N/A
|
||||
`bool IsUint()` | `unsigned GetUint()`
|
||||
`bool IsInt()` | `int GetInt()`
|
||||
`bool IsUint64()` | `uint64_t GetUint()`
|
||||
`bool IsUint64()` | `uint64_t GetUint64()`
|
||||
`bool IsInt64()` | `int64_t GetInt64()`
|
||||
`bool IsDouble()` | `double GetDouble()`
|
||||
|
||||
@ -292,12 +292,13 @@ The simple answer is performance. For fixed size JSON types (Number, True, False
|
||||
For example, if normal *copy* semantics was used:
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
Document d;
|
||||
Value o(kObjectType);
|
||||
{
|
||||
Value contacts(kArrayType);
|
||||
// adding elements to contacts array.
|
||||
// ...
|
||||
o.AddMember("contacts", contacts); // deep clone contacts (may be with lots of allocations)
|
||||
o.AddMember("contacts", contacts, d.GetAllocator()); // deep clone contacts (may be with lots of allocations)
|
||||
// destruct contacts.
|
||||
}
|
||||
~~~~~~~~~~
|
||||
@ -313,11 +314,12 @@ To make RapidJSON simple and fast, we chose to use *move* semantics for assignme
|
||||
So, with move semantics, the above example becomes:
|
||||
|
||||
~~~~~~~~~~cpp
|
||||
Document d;
|
||||
Value o(kObjectType);
|
||||
{
|
||||
Value contacts(kArrayType);
|
||||
// adding elements to contacts array.
|
||||
o.AddMember("contacts", contacts); // just memcpy() of contacts itself to the value of new member (16 bytes)
|
||||
o.AddMember("contacts", contacts, d.GetAllocator()); // just memcpy() of contacts itself to the value of new member (16 bytes)
|
||||
// contacts became Null here. Its destruction is trivial.
|
||||
}
|
||||
~~~~~~~~~~
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
本教程简介文件对象模型(Document Object Model, DOM)API。
|
||||
|
||||
如[用法一览](readme.zh-cn.md)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。
|
||||
如[用法一览](../readme.zh-cn.md#用法一览)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。
|
||||
|
||||
[TOC]
|
||||
|
||||
@ -123,7 +123,7 @@ a[3] = 4
|
||||
|
||||
你可以用整数字面量访问元素,如`a[0]`、`a[1]`、`a[2]`。
|
||||
|
||||
Array与`std::vector`相似,除了使用索引,也可使用迭待器来访问所有元素。
|
||||
Array与`std::vector`相似,除了使用索引,也可使用迭代器来访问所有元素。
|
||||
~~~~~~~~~~cpp
|
||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||
printf("%d ", itr->GetInt());
|
||||
@ -192,7 +192,7 @@ JSON只提供一种数值类型──Number。数字可以是整数或实数。R
|
||||
`bool IsNumber()` | 不适用
|
||||
`bool IsUint()` | `unsigned GetUint()`
|
||||
`bool IsInt()` | `int GetInt()`
|
||||
`bool IsUint64()` | `uint64_t GetUint()`
|
||||
`bool IsUint64()` | `uint64_t GetUint64()`
|
||||
`bool IsInt64()` | `int64_t GetInt64()`
|
||||
`bool IsDouble()` | `double GetDouble()`
|
||||
|
||||
@ -297,7 +297,7 @@ Value o(kObjectType);
|
||||
Value contacts(kArrayType);
|
||||
// 把元素加进contacts数组。
|
||||
// ...
|
||||
o.AddMember("contacts", contacts); // 深度复制contacts (可能有大量内存分配)
|
||||
o.AddMember("contacts", contacts, d.GetAllocator()); // 深度复制contacts (可能有大量内存分配)
|
||||
// 析构contacts。
|
||||
}
|
||||
~~~~~~~~~~
|
||||
@ -317,7 +317,7 @@ Value o(kObjectType);
|
||||
{
|
||||
Value contacts(kArrayType);
|
||||
// adding elements to contacts array.
|
||||
o.AddMember("contacts", contacts); // 只需 memcpy() contacts本身至新成员的Value(16字节)
|
||||
o.AddMember("contacts", contacts, d.GetAllocator()); // 只需 memcpy() contacts本身至新成员的Value(16字节)
|
||||
// contacts在这里变成Null。它的析构是平凡的。
|
||||
}
|
||||
~~~~~~~~~~
|
||||
@ -461,7 +461,7 @@ contact.AddMember(key, val, document.GetAllocator());
|
||||
|
||||
* `bool RemoveMember(const Ch* name)`:使用键名来移除成员(线性时间复杂度)。
|
||||
* `bool RemoveMember(const Value& name)`:除了`name`是一个Value,和上一行相同。
|
||||
* `MemberIterator RemoveMember(MemberIterator)`:使用迭待器移除成员(_常数_时间复杂度)。
|
||||
* `MemberIterator RemoveMember(MemberIterator)`:使用迭代器移除成员(_常数_时间复杂度)。
|
||||
* `MemberIterator EraseMember(MemberIterator)`:和上行相似但维持成员次序(线性时间复杂度)。
|
||||
* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`:移除一个范围内的成员,维持次序(线性时间复杂度)。
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com)
|
||||
# Distributed under the MIT License (see license.txt file)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(EXAMPLES
|
||||
capitalize
|
||||
@ -13,11 +14,13 @@ set(EXAMPLES
|
||||
simplereader
|
||||
simplewriter
|
||||
tutorial)
|
||||
|
||||
include_directories("../include/")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||
endif()
|
||||
|
@ -27,7 +27,7 @@ struct CapitalizeFilter {
|
||||
bool String(const char* str, SizeType length, bool) {
|
||||
buffer_.clear();
|
||||
for (SizeType i = 0; i < length; i++)
|
||||
buffer_.push_back(std::toupper(str[i]));
|
||||
buffer_.push_back(static_cast<char>(std::toupper(str[i])));
|
||||
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
|
||||
}
|
||||
bool StartObject() { return out_.StartObject(); }
|
||||
@ -58,7 +58,7 @@ int main(int, char*[]) {
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
|
||||
if (!reader.Parse(is, filter)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ int main(int, char*[]) {
|
||||
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
if (!reader.Parse(is, writer)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,11 @@ RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
#endif
|
||||
|
||||
struct MessageHandler
|
||||
: public BaseReaderHandler<UTF8<>, MessageHandler> {
|
||||
MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
|
||||
@ -63,7 +68,11 @@ struct MessageHandler
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
void ParseMessages(const char* json, MessageMap& messages) {
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
static void ParseMessages(const char* json, MessageMap& messages) {
|
||||
Reader reader;
|
||||
MessageHandler handler;
|
||||
StringStream ss(json);
|
||||
|
@ -22,7 +22,7 @@ int main(int, char*[]) {
|
||||
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ int main(int, char*[]) {
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
||||
if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,10 @@ protected:
|
||||
void Serialize(Writer& writer) const {
|
||||
// This base class just write out name-value pairs, without wrapping within an object.
|
||||
writer.String("name");
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(name_);
|
||||
#else
|
||||
writer.String(name_.c_str(), (SizeType)name_.length()); // Supplying length of string is faster.
|
||||
writer.String(name_.c_str(), static_cast<SizeType>(name_.length())); // Supplying length of string is faster.
|
||||
#endif
|
||||
writer.String("age");
|
||||
writer.Uint(age_);
|
||||
@ -44,10 +44,10 @@ public:
|
||||
writer.StartObject();
|
||||
|
||||
writer.String("school");
|
||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(school_);
|
||||
#else
|
||||
writer.String(school_.c_str(), (SizeType)school_.length());
|
||||
writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
|
||||
#endif
|
||||
|
||||
writer.String("GPA");
|
||||
|
@ -121,17 +121,17 @@ int main(int, char*[]) {
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer[10];
|
||||
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
char buffer2[10];
|
||||
int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
|
||||
author.SetString(buffer, static_cast<size_t>(len), document.GetAllocator());
|
||||
author.SetString(buffer2, static_cast<SizeType>(len), document.GetAllocator());
|
||||
// Shorter but slower version:
|
||||
// document["hello"].SetString(buffer, document.GetAllocator());
|
||||
|
||||
// Constructor version:
|
||||
// Value author(buffer, len, document.GetAllocator());
|
||||
// Value author(buffer, document.GetAllocator());
|
||||
memset(buffer, 0, sizeof(buffer)); // For demonstration purpose.
|
||||
memset(buffer2, 0, sizeof(buffer2)); // For demonstration purpose.
|
||||
}
|
||||
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||
document.AddMember("author", author, document.GetAllocator());
|
||||
|
@ -62,8 +62,20 @@ concept Allocator {
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return std::malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); }
|
||||
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;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
@ -131,11 +143,13 @@ public:
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
@ -160,11 +174,14 @@ public:
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
@ -174,12 +191,15 @@ public:
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
increment = RAPIDJSON_ALIGN(increment);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
@ -191,7 +211,9 @@ public:
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
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)
|
||||
@ -209,7 +231,7 @@ private:
|
||||
void AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
|
@ -25,36 +25,19 @@
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#elif defined(__GNUC__)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#endif
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable RapidJSON support for \c std::string
|
||||
|
||||
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||
for construction and comparison.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
#include <string>
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
||||
#endif
|
||||
@ -69,6 +52,9 @@ RAPIDJSON_NAMESPACE_BEGIN
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericValue;
|
||||
|
||||
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||
class GenericDocument;
|
||||
|
||||
//! Name-value pair in a JSON object value.
|
||||
/*!
|
||||
This class was internal to GenericValue. It used to be a inner struct.
|
||||
@ -257,6 +243,7 @@ struct GenericStringRef {
|
||||
typedef CharType Ch; //!< character type of the string
|
||||
|
||||
//! Create string reference from \c const character array
|
||||
#ifndef __clang__ // -Wdocumentation
|
||||
/*!
|
||||
This constructor implicitly creates a constant string reference from
|
||||
a \c const character array. It has better performance than
|
||||
@ -279,11 +266,13 @@ struct GenericStringRef {
|
||||
In such cases, the referenced string should be \b copied to the
|
||||
GenericValue instead.
|
||||
*/
|
||||
#endif
|
||||
template<SizeType N>
|
||||
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
|
||||
: s(str), length(N-1) {}
|
||||
|
||||
//! Explicitly create string reference from \c const character pointer
|
||||
#ifndef __clang__ // -Wdocumentation
|
||||
/*!
|
||||
This constructor can be used to \b explicitly create a reference to
|
||||
a constant string pointer.
|
||||
@ -302,16 +291,19 @@ struct GenericStringRef {
|
||||
In such cases, the referenced string should be \b copied to the
|
||||
GenericValue instead.
|
||||
*/
|
||||
#endif
|
||||
explicit GenericStringRef(const CharType* str)
|
||||
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
|
||||
|
||||
//! Create constant string reference from pointer and length
|
||||
#ifndef __clang__ // -Wdocumentation
|
||||
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
|
||||
\param len length of the string, excluding the trailing NULL terminator
|
||||
|
||||
\post \ref s == str && \ref length == len
|
||||
\note Constant complexity.
|
||||
*/
|
||||
#endif
|
||||
GenericStringRef(const CharType* str, SizeType len)
|
||||
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
|
||||
|
||||
@ -427,6 +419,7 @@ public:
|
||||
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
||||
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
||||
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
|
||||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
|
||||
|
||||
//!@name Constructors and destructor.
|
||||
//@{
|
||||
@ -445,6 +438,16 @@ private:
|
||||
//! Copy constructor is not permitted.
|
||||
GenericValue(const GenericValue& rhs);
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
//! Moving from a GenericDocument is not permitted.
|
||||
template <typename StackAllocator>
|
||||
GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
|
||||
|
||||
//! Move assignment from a GenericDocument is not permitted.
|
||||
template <typename StackAllocator>
|
||||
GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor with JSON value type.
|
||||
@ -640,7 +643,7 @@ public:
|
||||
*/
|
||||
template <typename SourceAllocator>
|
||||
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
|
||||
RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
|
||||
this->~GenericValue();
|
||||
new (this) GenericValue(rhs, allocator);
|
||||
return *this;
|
||||
@ -659,6 +662,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! free-standing swap function helper
|
||||
/*!
|
||||
Helper function to enable support for common swap implementation pattern based on \c std::swap:
|
||||
\code
|
||||
void swap(MyClass& a, MyClass& b) {
|
||||
using std::swap;
|
||||
swap(a.value, b.value);
|
||||
// ...
|
||||
}
|
||||
\endcode
|
||||
\see Swap()
|
||||
*/
|
||||
friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
|
||||
|
||||
//! Prepare Value for move semantics
|
||||
/*! \return *this */
|
||||
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
|
||||
@ -708,7 +725,7 @@ public:
|
||||
else
|
||||
return data_.n.u64 == rhs.data_.n.u64;
|
||||
|
||||
default: // kTrueType, kFalseType, kNullType
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -836,13 +853,25 @@ public:
|
||||
return member->value;
|
||||
else {
|
||||
RAPIDJSON_ASSERT(false); // see above note
|
||||
static GenericValue NullValue;
|
||||
return NullValue;
|
||||
|
||||
// This will generate -Wexit-time-destructors in clang
|
||||
// static GenericValue NullValue;
|
||||
// return NullValue;
|
||||
|
||||
// Use static buffer and placement-new to prevent destruction
|
||||
static char buffer[sizeof(GenericValue)];
|
||||
return *new (buffer) GenericValue();
|
||||
}
|
||||
}
|
||||
template <typename SourceAllocator>
|
||||
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Get a value from an object associated with name (string object).
|
||||
GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
|
||||
const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
|
||||
#endif
|
||||
|
||||
//! Const member iterator
|
||||
/*! \pre IsObject() == true */
|
||||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
|
||||
@ -866,6 +895,18 @@ public:
|
||||
*/
|
||||
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Check whether a member exists in the object with string object.
|
||||
/*!
|
||||
\param name Member name to be searched.
|
||||
\pre IsObject() == true
|
||||
\return Whether a member with that name exists.
|
||||
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
||||
\note Linear time complexity.
|
||||
*/
|
||||
bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
|
||||
#endif
|
||||
|
||||
//! Check whether a member exists in the object with GenericValue name.
|
||||
/*!
|
||||
This version is faster because it does not need a StrLen(). It can also handle string with null character.
|
||||
@ -922,6 +963,18 @@ public:
|
||||
}
|
||||
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Find member by string object name.
|
||||
/*!
|
||||
\param name Member name to be searched.
|
||||
\pre IsObject() == true
|
||||
\return Iterator to member, if it exists.
|
||||
Otherwise returns \ref MemberEnd().
|
||||
*/
|
||||
MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
|
||||
ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
|
||||
#endif
|
||||
|
||||
//! Add a member (name-value pair) to the object.
|
||||
/*! \param name A string value as name of member.
|
||||
\param value Value of any type.
|
||||
@ -968,6 +1021,22 @@ public:
|
||||
return AddMember(name, v, allocator);
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
//! Add a string object as member (name-value pair) to the object.
|
||||
/*! \param name A string value as name of member.
|
||||
\param value constant string reference as value of member.
|
||||
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||
\return The value itself for fluent API.
|
||||
\pre IsObject()
|
||||
\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
|
||||
\note Amortized Constant time complexity.
|
||||
*/
|
||||
GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
|
||||
GenericValue v(value, allocator);
|
||||
return AddMember(name, v, allocator);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Add any primitive value as member (name-value pair) to the object.
|
||||
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
|
||||
\param name A string value as name of member.
|
||||
@ -1086,6 +1155,10 @@ public:
|
||||
return RemoveMember(n);
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
|
||||
#endif
|
||||
|
||||
template <typename SourceAllocator>
|
||||
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator m = FindMember(name);
|
||||
@ -1157,11 +1230,36 @@ public:
|
||||
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
||||
for (MemberIterator itr = pos; itr != last; ++itr)
|
||||
itr->~Member();
|
||||
std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));
|
||||
data_.o.size -= (last - first);
|
||||
std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
|
||||
data_.o.size -= static_cast<SizeType>(last - first);
|
||||
return pos;
|
||||
}
|
||||
|
||||
//! Erase a member in object by its name.
|
||||
/*! \param name Name of member to be removed.
|
||||
\return Whether the member existed.
|
||||
\note Linear time complexity.
|
||||
*/
|
||||
bool EraseMember(const Ch* name) {
|
||||
GenericValue n(StringRef(name));
|
||||
return EraseMember(n);
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
|
||||
#endif
|
||||
|
||||
template <typename SourceAllocator>
|
||||
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator m = FindMember(name);
|
||||
if (m != MemberEnd()) {
|
||||
EraseMember(m);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Array
|
||||
@ -1225,7 +1323,7 @@ public:
|
||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
if (newCapacity > data_.a.capacity) {
|
||||
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
|
||||
data_.a.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
|
||||
data_.a.capacity = newCapacity;
|
||||
}
|
||||
return *this;
|
||||
@ -1332,8 +1430,8 @@ public:
|
||||
ValueIterator pos = Begin() + (first - Begin());
|
||||
for (ValueIterator itr = pos; itr != last; ++itr)
|
||||
itr->~GenericValue();
|
||||
std::memmove(pos, last, (End() - last) * sizeof(GenericValue));
|
||||
data_.a.size -= (last - first);
|
||||
std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
|
||||
data_.a.size -= static_cast<SizeType>(last - first);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@ -1352,8 +1450,8 @@ public:
|
||||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
||||
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
|
||||
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
|
||||
if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
|
||||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
|
||||
if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
|
||||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
|
||||
}
|
||||
|
||||
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
|
||||
@ -1417,7 +1515,7 @@ public:
|
||||
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
|
||||
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
|
||||
*/
|
||||
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); }
|
||||
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
|
||||
#endif
|
||||
|
||||
//@}
|
||||
@ -1525,9 +1623,9 @@ private:
|
||||
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
||||
Ch str[MaxChars];
|
||||
|
||||
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
||||
inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); }
|
||||
inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
|
||||
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
||||
inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
|
||||
inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
|
||||
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
||||
@ -1579,16 +1677,24 @@ private:
|
||||
// Initialize this value as array with initial data, without calling destructor.
|
||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
||||
flags_ = kArrayFlag;
|
||||
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
|
||||
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
||||
if (count) {
|
||||
data_.a.elements = static_cast<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;
|
||||
}
|
||||
|
||||
//! Initialize this value as object with initial data, without calling destructor.
|
||||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
||||
flags_ = kObjectFlag;
|
||||
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
|
||||
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
||||
if (count) {
|
||||
data_.o.members = static_cast<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;
|
||||
}
|
||||
|
||||
@ -1609,7 +1715,7 @@ private:
|
||||
} else {
|
||||
flags_ = kCopyStringFlag;
|
||||
data_.s.length = s.length;
|
||||
str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
||||
str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
|
||||
data_.s.str = str;
|
||||
}
|
||||
std::memcpy(str, s, s.length * sizeof(Ch));
|
||||
@ -1665,7 +1771,22 @@ public:
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
|
||||
//! Constructor
|
||||
/*! \param allocator Optional allocator for allocating memory.
|
||||
/*! Creates an empty document of specified type.
|
||||
\param type Mandatory type of object to create.
|
||||
\param allocator Optional allocator for allocating memory.
|
||||
\param stackCapacity Optional initial capacity of stack in bytes.
|
||||
\param stackAllocator Optional allocator for allocating memory for stack.
|
||||
*/
|
||||
explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
|
||||
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
|
||||
{
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
/*! Creates an empty document which type is Null.
|
||||
\param allocator Optional allocator for allocating memory.
|
||||
\param stackCapacity Optional initial capacity of stack in bytes.
|
||||
\param stackAllocator Optional allocator for allocating memory for stack.
|
||||
*/
|
||||
@ -1679,7 +1800,7 @@ public:
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
//! Move constructor in C++11
|
||||
GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
|
||||
: ValueType(std::move(rhs)),
|
||||
: ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
|
||||
allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(std::move(rhs.stack_)),
|
||||
@ -1719,6 +1840,35 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Exchange the contents of this document with those of another.
|
||||
/*!
|
||||
\param rhs Another document.
|
||||
\note Constant complexity.
|
||||
\see GenericValue::Swap
|
||||
*/
|
||||
GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
|
||||
ValueType::Swap(rhs);
|
||||
stack_.Swap(rhs.stack_);
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(parseResult_, rhs.parseResult_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! free-standing swap function helper
|
||||
/*!
|
||||
Helper function to enable support for common swap implementation pattern based on \c std::swap:
|
||||
\code
|
||||
void swap(MyClass& a, MyClass& b) {
|
||||
using std::swap;
|
||||
swap(a.doc, b.doc);
|
||||
// ...
|
||||
}
|
||||
\endcode
|
||||
\see Swap()
|
||||
*/
|
||||
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
|
||||
|
||||
//!@name Parse from stream
|
||||
//!@{
|
||||
|
||||
@ -1731,13 +1881,13 @@ public:
|
||||
*/
|
||||
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
|
||||
GenericDocument& ParseStream(InputStream& is) {
|
||||
ValueType::SetNull(); // Remove existing root if exist
|
||||
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
|
||||
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
|
||||
stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
|
||||
ClearStackOnExit scope(*this);
|
||||
parseResult_ = reader.template Parse<parseFlags>(is, *this);
|
||||
if (parseResult_) {
|
||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
||||
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
|
||||
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -1796,7 +1946,7 @@ public:
|
||||
\param str Read-only zero-terminated string to be parsed.
|
||||
*/
|
||||
template <unsigned parseFlags, typename SourceEncoding>
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
|
||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||
GenericStringStream<SourceEncoding> s(str);
|
||||
return ParseStream<parseFlags, SourceEncoding>(s);
|
||||
@ -1831,10 +1981,26 @@ public:
|
||||
//! Get the position of last parsing error in input, 0 otherwise.
|
||||
size_t GetErrorOffset() const { return parseResult_.Offset(); }
|
||||
|
||||
//! Implicit conversion to get the last parse result
|
||||
#ifndef __clang // -Wdocumentation
|
||||
/*! \return \ref ParseResult of the last parse operation
|
||||
|
||||
\code
|
||||
Document doc;
|
||||
ParseResult ok = doc.Parse(json);
|
||||
if (!ok)
|
||||
printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
|
||||
\endcode
|
||||
*/
|
||||
#endif
|
||||
operator ParseResult() const { return parseResult_; }
|
||||
//!@}
|
||||
|
||||
//! Get the allocator of this document.
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
//! Get the capacity of stack in bytes.
|
||||
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
||||
@ -1877,7 +2043,7 @@ private:
|
||||
|
||||
bool EndObject(SizeType memberCount) {
|
||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
||||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
||||
stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1940,15 +2106,24 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
|
||||
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
|
||||
}
|
||||
break;
|
||||
default: // kNumberType, kTrueType, kFalseType, kNullType
|
||||
default:
|
||||
flags_ = rhs.flags_;
|
||||
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(_MSC_VER) || defined(__GNUC__)
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Input byte stream wrapper with a statically bound encoding.
|
||||
@ -60,7 +65,7 @@ private:
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
@ -77,8 +82,8 @@ public:
|
||||
void Flush() { os_.Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
@ -142,11 +147,11 @@ private:
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = (const unsigned char *)is_->Peek4();
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
@ -193,7 +198,7 @@ private:
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam InputByteStream type of output byte stream to be wrapped.
|
||||
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
@ -227,8 +232,8 @@ public:
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
@ -254,6 +259,10 @@ private:
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -122,17 +122,17 @@ struct UTF8 {
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c = is.Take();
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = (unsigned char)c;
|
||||
*codepoint = static_cast<unsigned char>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange((unsigned char)c);
|
||||
*codepoint = (0xFF >> type) & (unsigned char)c;
|
||||
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
|
||||
bool result = true;
|
||||
switch (type) {
|
||||
case 2: TAIL(); return result;
|
||||
@ -152,7 +152,7 @@ struct UTF8 {
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define COPY() os.Put(c = is.Take())
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c;
|
||||
COPY();
|
||||
@ -160,7 +160,7 @@ struct UTF8 {
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange((unsigned char)c)) {
|
||||
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||
case 2: TAIL(); return result;
|
||||
case 3: TAIL(); TAIL(); return result;
|
||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||
@ -196,12 +196,12 @@ struct UTF8 {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
if ((unsigned char)c != 0xEFu) return c;
|
||||
typename InputByteStream::Ch c = Take(is);
|
||||
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBBu) return c;
|
||||
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBFu) return c;
|
||||
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
@ -209,13 +209,15 @@ struct UTF8 {
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
@ -262,15 +264,15 @@ struct UTF16 {
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
Ch c = is.Take();
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = c;
|
||||
*codepoint = static_cast<unsigned>(c);
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (c & 0x3FF) << 10;
|
||||
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (c & 0x3FF);
|
||||
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
@ -281,8 +283,8 @@ struct UTF16 {
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
typename InputStream::Ch c;
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||
if (c < 0xD800 || c > 0xDFFF)
|
||||
return true;
|
||||
else if (c <= 0xDBFF) {
|
||||
@ -300,28 +302,29 @@ struct UTF16LE : UTF16<CharType> {
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
return c;
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
@ -332,28 +335,29 @@ struct UTF16BE : UTF16<CharType> {
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<uint8_t>(is.Take());
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFEu); os.Put(0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
@ -406,32 +410,35 @@ struct UTF32LE : UTF32<CharType> {
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 24;
|
||||
return c;
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
@ -442,32 +449,35 @@ struct UTF32BE : UTF32<CharType> {
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 24;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
@ -493,29 +503,29 @@ struct ASCII {
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
unsigned char c = static_cast<unsigned char>(is.Take());
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
unsigned char c = is.Take();
|
||||
os.Put(c);
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
return c;
|
||||
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||
return static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
@ -618,7 +628,7 @@ struct Transcoder<Encoding, Encoding> {
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSV_VER)
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
@ -12,11 +12,17 @@
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||
#define RAPIDJSON_ERROR_EN_H__
|
||||
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||
#define RAPIDJSON_ERROR_EN_H_
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
@ -55,11 +61,14 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
|
||||
default:
|
||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H__
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H_
|
||||
|
@ -12,8 +12,15 @@
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||
#define RAPIDJSON_ERROR_ERROR_H__
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||
#define RAPIDJSON_ERROR_ERROR_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
/*! \file error.h */
|
||||
|
||||
@ -97,7 +104,7 @@ enum ParseErrorCode {
|
||||
\see GenericReader::Parse, GenericDocument::Parse
|
||||
*/
|
||||
struct ParseResult {
|
||||
|
||||
public:
|
||||
//! Default constructor, no error.
|
||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||
//! Constructor to set an error.
|
||||
@ -141,4 +148,8 @@ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H__
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H_
|
||||
|
@ -18,6 +18,13 @@
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
@ -85,4 +92,8 @@ private:
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
|
@ -18,6 +18,11 @@
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
@ -57,7 +62,11 @@ public:
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
@ -88,4 +97,8 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
@ -50,7 +51,16 @@ public:
|
||||
if (length > 0)
|
||||
AppendDecimal64(decimals + i, decimals + i + length);
|
||||
}
|
||||
|
||||
|
||||
BigInteger& operator=(const BigInteger &rhs)
|
||||
{
|
||||
if (this != &rhs) {
|
||||
count_ = rhs.count_;
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator=(uint64_t u) {
|
||||
digits_[0] = u;
|
||||
count_ = 1;
|
||||
@ -97,7 +107,7 @@ public:
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint32_t k = 0;
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
const uint64_t c = digits_[i] >> 32;
|
||||
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||
@ -230,7 +240,7 @@ private:
|
||||
uint64_t r = 0;
|
||||
for (const char* p = begin; p != end; ++p) {
|
||||
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||
r = r * 10 + (*p - '0');
|
||||
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -246,7 +256,7 @@ private:
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||
p += k;
|
||||
*outHigh = p >> 64;
|
||||
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||
return static_cast<uint64_t>(p);
|
||||
#else
|
||||
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||
|
@ -19,11 +19,12 @@
|
||||
#ifndef RAPIDJSON_DIYFP_H_
|
||||
#define RAPIDJSON_DIYFP_H_
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
#include <intrin.h>
|
||||
#if defined(_M_AMD64)
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#endif
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
@ -34,6 +35,11 @@ RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
struct DiyFp {
|
||||
DiyFp() {}
|
||||
|
||||
@ -45,7 +51,7 @@ struct DiyFp {
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
|
||||
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
|
||||
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
@ -71,7 +77,7 @@ struct DiyFp {
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||
uint64_t h = p >> 64;
|
||||
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||
uint64_t l = static_cast<uint64_t>(p);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
@ -232,8 +238,8 @@ inline DiyFp GetCachedPower(int e, int* K) {
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||
unsigned index = (exp + 348) / 8;
|
||||
*outExp = -348 + index * 8;
|
||||
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
||||
*outExp = -348 + static_cast<int>(index) * 8;
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
@ -241,6 +247,11 @@ inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
|
@ -62,7 +62,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
uint64_t p2 = Mp.f & (one.f - 1);
|
||||
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||
*len = 0;
|
||||
|
||||
while (kappa > 0) {
|
||||
@ -101,7 +101,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
|
||||
kappa--;
|
||||
if (p2 < delta) {
|
||||
*K += kappa;
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -158,14 +158,14 @@ inline char* Prettify(char* buffer, int length, int k) {
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
std::memmove(&buffer[kk + 1], &buffer[kk], length - kk);
|
||||
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||
buffer[kk] = '.';
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
std::memmove(&buffer[offset], &buffer[0], length);
|
||||
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
@ -179,7 +179,7 @@ inline char* Prettify(char* buffer, int length, int k) {
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
std::memmove(&buffer[2], &buffer[1], length - 1);
|
||||
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
|
@ -23,29 +23,29 @@ namespace internal {
|
||||
class Double {
|
||||
public:
|
||||
Double() {}
|
||||
Double(double d) : d(d) {}
|
||||
Double(uint64_t u) : u(u) {}
|
||||
Double(double d) : d_(d) {}
|
||||
Double(uint64_t u) : u_(u) {}
|
||||
|
||||
double Value() const { return d; }
|
||||
uint64_t Uint64Value() const { return u; }
|
||||
double Value() const { return d_; }
|
||||
uint64_t Uint64Value() const { return u_; }
|
||||
|
||||
double NextPositiveDouble() const {
|
||||
RAPIDJSON_ASSERT(!Sign());
|
||||
return Double(u + 1).Value();
|
||||
return Double(u_ + 1).Value();
|
||||
}
|
||||
|
||||
bool Sign() const { return (u & kSignMask) != 0; }
|
||||
uint64_t Significand() const { return u & kSignificandMask; }
|
||||
int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; }
|
||||
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||
|
||||
bool IsNan() 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 IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; }
|
||||
bool IsNan() 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 IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||
|
||||
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||
uint64_t ToBias() const { return (u & kSignMask) ? ~u + 1 : u | kSignMask; }
|
||||
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||
|
||||
static unsigned EffectiveSignificandSize(int order) {
|
||||
if (order >= -1021)
|
||||
@ -53,7 +53,7 @@ public:
|
||||
else if (order <= -1074)
|
||||
return 0;
|
||||
else
|
||||
return order + 1074;
|
||||
return static_cast<unsigned>(order) + 1074;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -66,8 +66,8 @@ private:
|
||||
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
double d_;
|
||||
uint64_t u_;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -15,9 +15,7 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#error <rapidjson.h> not yet included. Do not include this file directly.
|
||||
#endif
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
#include "swap.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
@ -79,6 +82,15 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
@ -120,9 +132,16 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
@ -149,7 +168,7 @@ private:
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
|
@ -95,13 +95,13 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
||||
BigInteger dS = d;
|
||||
dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||
|
||||
BigInteger delta(0);
|
||||
dS.Difference(bS, &delta);
|
||||
@ -134,7 +134,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||
break;
|
||||
significand = significand * 10 + (decimals[i] - '0');
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||
}
|
||||
|
||||
if (i < length && decimals[i] >= '5') // Rounding
|
||||
@ -149,7 +149,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
v = v.Normalize();
|
||||
error <<= -v.e;
|
||||
|
||||
const int dExp = (int)decimalPosition - (int)i + exp;
|
||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
||||
|
||||
int actualExp;
|
||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||
@ -163,10 +163,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||
};
|
||||
int adjustment = dExp - actualExp - 1;
|
||||
int adjustment = dExp - actualExp - 1;
|
||||
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||
v = v * kPow10[adjustment];
|
||||
if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
|
||||
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||
error += kUlp / 2;
|
||||
}
|
||||
|
||||
@ -184,24 +184,29 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
||||
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
|
||||
v.f >>= scaleExp;
|
||||
v.e += scaleExp;
|
||||
error = (error >> scaleExp) + 1 + kUlp;
|
||||
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
|
||||
precisionSize -= scaleExp;
|
||||
}
|
||||
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
|
||||
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||
if (precisionBits >= halfWay + error)
|
||||
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||
rounded.f++;
|
||||
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||
rounded.f >>= 1;
|
||||
rounded.e++;
|
||||
}
|
||||
}
|
||||
|
||||
*result = rounded.ToDouble();
|
||||
|
||||
return halfWay - error >= precisionBits || precisionBits >= halfWay + error;
|
||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||
}
|
||||
|
||||
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
const BigInteger dInt(decimals, length);
|
||||
const int dExp = (int)decimalPosition - (int)length + exp;
|
||||
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
||||
Double a(approx);
|
||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||
if (cmp < 0)
|
||||
@ -241,10 +246,10 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
|
||||
|
||||
// Trim right-most digits
|
||||
const int kMaxDecimalDigit = 780;
|
||||
if ((int)length > kMaxDecimalDigit) {
|
||||
int delta = (int(length) - kMaxDecimalDigit);
|
||||
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
||||
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
||||
exp += delta;
|
||||
decimalPosition -= delta;
|
||||
decimalPosition -= static_cast<unsigned>(delta);
|
||||
length = kMaxDecimalDigit;
|
||||
}
|
||||
|
||||
|
37
include/rapidjson/internal/swap.h
Normal file
@ -0,0 +1,37 @@
|
||||
// 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_INTERNAL_SWAP_H_
|
||||
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
@ -17,6 +17,12 @@
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory input byte stream.
|
||||
@ -58,4 +64,8 @@ struct MemoryStream {
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||
|
@ -89,14 +89,14 @@
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler would give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
1326
include/rapidjson/pointer.h
Normal file
@ -186,7 +186,7 @@ protected:
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, indentChar_, count);
|
||||
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
|
@ -15,12 +15,9 @@
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
/*!\file rapidjson.h
|
||||
\brief common definitions and configuration
|
||||
|
||||
|
||||
\see RAPIDJSON_CONFIG
|
||||
*/
|
||||
|
||||
@ -42,6 +39,40 @@
|
||||
#include <cstdlib> // malloc(), realloc(), free(), size_t
|
||||
#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 2
|
||||
#define RAPIDJSON_VERSION_STRING \
|
||||
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NAMESPACE_(BEGIN|END)
|
||||
/*! \def RAPIDJSON_NAMESPACE
|
||||
@ -88,6 +119,31 @@
|
||||
#define RAPIDJSON_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#endif
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable RapidJSON support for \c std::string
|
||||
|
||||
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||
for construction and comparison.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
#include <string>
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
@ -180,6 +236,8 @@
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_MSC_VER) && defined(_M_ARM)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||
# define RAPIDJSON_ENDIAN
|
||||
# else
|
||||
@ -192,7 +250,7 @@
|
||||
|
||||
//! Whether using 64-bit architecture
|
||||
#ifndef RAPIDJSON_64BIT
|
||||
#if defined(__LP64__) || defined(_WIN64)
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
|
||||
#define RAPIDJSON_64BIT 1
|
||||
#else
|
||||
#define RAPIDJSON_64BIT 0
|
||||
@ -207,10 +265,14 @@
|
||||
\param x pointer to align
|
||||
|
||||
Some machines require strict data alignment. Currently the default uses 4 bytes
|
||||
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,
|
||||
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ALIGN
|
||||
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
|
||||
#if RAPIDJSON_64BIT == 1
|
||||
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
|
||||
#else
|
||||
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -314,7 +376,9 @@ RAPIDJSON_NAMESPACE_END
|
||||
|
||||
// Adopt from boost
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
#ifndef __clang__
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#endif
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
@ -330,7 +394,9 @@ RAPIDJSON_NAMESPACE_END
|
||||
#else
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
#ifndef __clang__
|
||||
//!@endcond
|
||||
#endif
|
||||
|
||||
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||
\brief (Internal) macro to check for conditions at compile-time
|
||||
@ -385,10 +451,6 @@ RAPIDJSON_NAMESPACE_END
|
||||
#define RAPIDJSON_VERSION_CODE(x,y,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
|
||||
|
||||
|
@ -39,6 +39,12 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
@ -140,6 +146,7 @@ enum ParseFlag {
|
||||
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
|
||||
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
|
||||
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
|
||||
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
|
||||
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||
};
|
||||
|
||||
@ -255,27 +262,27 @@ void SkipWhitespace(InputStream& is) {
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
// Fast return for single non-whitespace
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
// Fast return for single non-whitespace
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
|
||||
// 16-byte align to the next boundary
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
// 16-byte align to the next boundary
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
|
||||
// The rest of string using SIMD
|
||||
static const char whitespace[16] = " \n\r\t";
|
||||
const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]);
|
||||
static const char whitespace[16] = " \n\r\t";
|
||||
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
|
||||
|
||||
for (;; p += 16) {
|
||||
const __m128i s = _mm_load_si128((const __m128i *)p);
|
||||
const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
|
||||
if (r != 0) { // some of characters is non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
@ -292,39 +299,39 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
|
||||
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
// Fast return for single non-whitespace
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
// Fast return for single non-whitespace
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
|
||||
// 16-byte align to the next boundary
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
|
||||
// The rest of string
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\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",
|
||||
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\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",
|
||||
"\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 w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][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 w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
|
||||
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
|
||||
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
|
||||
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
|
||||
|
||||
for (;; p += 16) {
|
||||
const __m128i s = _mm_load_si128((const __m128i *)p);
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
__m128i x = _mm_cmpeq_epi8(s, w0);
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
|
||||
unsigned short r = (unsigned short)~_mm_movemask_epi8(x);
|
||||
unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
|
||||
if (r != 0) { // some of characters may be non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
@ -398,7 +405,8 @@ public:
|
||||
|
||||
ClearStackOnExit scope(*this);
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (is.Peek() == '\0') {
|
||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||
@ -409,7 +417,8 @@ public:
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (is.Peek() != '\0') {
|
||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||
@ -462,6 +471,40 @@ private:
|
||||
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
||||
};
|
||||
|
||||
template<unsigned parseFlags, typename InputStream>
|
||||
void SkipWhitespaceAndComments(InputStream& is) {
|
||||
SkipWhitespace(is);
|
||||
|
||||
if (parseFlags & kParseCommentsFlag) {
|
||||
while (is.Peek() == '/') {
|
||||
is.Take();
|
||||
|
||||
if (is.Peek() == '*') {
|
||||
is.Take();
|
||||
while (true) {
|
||||
if (is.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
|
||||
if (is.Take() == '*') {
|
||||
if (is.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
|
||||
if (is.Take() == '/')
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (is.Peek() == '/') {
|
||||
is.Take();
|
||||
while (is.Peek() != '\0' && is.Take() != '\n') { }
|
||||
} else {
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
}
|
||||
|
||||
SkipWhitespace(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse object: { string : value, ... }
|
||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||
void ParseObject(InputStream& is, Handler& handler) {
|
||||
@ -471,7 +514,8 @@ private:
|
||||
if (!handler.StartObject())
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Peek() == '}') {
|
||||
is.Take();
|
||||
@ -487,27 +531,35 @@ private:
|
||||
ParseString<parseFlags>(is, handler, true);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Take() != ':')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
ParseValue<parseFlags>(is, handler);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
++memberCount;
|
||||
|
||||
switch (is.Take()) {
|
||||
case ',': SkipWhitespace(is); break;
|
||||
case ',':
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
break;
|
||||
case '}':
|
||||
if (!handler.EndObject(memberCount))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
default:
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -521,7 +573,8 @@ private:
|
||||
if (!handler.StartArray())
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Peek() == ']') {
|
||||
is.Take();
|
||||
@ -535,15 +588,21 @@ private:
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
++elementCount;
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
switch (is.Take()) {
|
||||
case ',': SkipWhitespace(is); break;
|
||||
case ',':
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
break;
|
||||
case ']':
|
||||
if (!handler.EndArray(elementCount))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
default:
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -645,7 +704,7 @@ private:
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
size_t length = s.PutEnd(head) - 1;
|
||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;
|
||||
const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
|
||||
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
|
||||
}
|
||||
else {
|
||||
@ -684,9 +743,8 @@ private:
|
||||
if (c == '\\') { // Escape
|
||||
is.Take();
|
||||
Ch e = is.Take();
|
||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
|
||||
os.Put(escape[(unsigned char)e]);
|
||||
}
|
||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[static_cast<unsigned char>(e)])
|
||||
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
||||
else if (e == 'u') { // Unicode
|
||||
unsigned codepoint = ParseHex4(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
@ -712,7 +770,7 @@ private:
|
||||
}
|
||||
else if (c == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
||||
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
else if (static_cast<unsigned>(c) < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||
else {
|
||||
if (parseFlags & kParseValidateEncodingFlag ?
|
||||
@ -753,7 +811,7 @@ private:
|
||||
~NumberStream() {}
|
||||
|
||||
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
||||
stackStream.Put((char)Base::is.Peek());
|
||||
stackStream.Put(static_cast<char>(Base::is.Peek()));
|
||||
return Base::is.Take();
|
||||
}
|
||||
|
||||
@ -884,10 +942,10 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
d = (double)i64;
|
||||
d = static_cast<double>(i64);
|
||||
#else
|
||||
// Use double to store significand in 32-bit architecture
|
||||
d = use64bit ? (double)i64 : (double)i;
|
||||
d = static_cast<double>(use64bit ? i64 : i);
|
||||
#endif
|
||||
useDouble = true;
|
||||
}
|
||||
@ -924,11 +982,23 @@ private:
|
||||
}
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = s.Take() - '0';
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + (s.Take() - '0');
|
||||
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first.
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
exp = static_cast<int>(s.Take() - '0');
|
||||
if (expMinus) {
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||
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 + static_cast<int>(s.Take() - '0');
|
||||
if (exp > maxExp)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -955,13 +1025,13 @@ private:
|
||||
else {
|
||||
if (use64bit) {
|
||||
if (minus)
|
||||
cont = handler.Int64(-(int64_t)i64);
|
||||
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
|
||||
else
|
||||
cont = handler.Uint64(i64);
|
||||
}
|
||||
else {
|
||||
if (minus)
|
||||
cont = handler.Int(-(int)i);
|
||||
cont = handler.Int(static_cast<int32_t>(~i + 1));
|
||||
else
|
||||
cont = handler.Uint(i);
|
||||
}
|
||||
@ -980,7 +1050,10 @@ private:
|
||||
case '"': ParseString<parseFlags>(is, handler); break;
|
||||
case '{': ParseObject<parseFlags>(is, handler); break;
|
||||
case '[': ParseArray <parseFlags>(is, handler); break;
|
||||
default : ParseNumber<parseFlags>(is, handler);
|
||||
default :
|
||||
ParseNumber<parseFlags>(is, handler);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1007,11 +1080,11 @@ private:
|
||||
IterativeParsingArrayFinishState,
|
||||
|
||||
// Single value state
|
||||
IterativeParsingValueState,
|
||||
|
||||
cIterativeParsingStateCount
|
||||
IterativeParsingValueState
|
||||
};
|
||||
|
||||
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
|
||||
|
||||
// Tokens
|
||||
enum Token {
|
||||
LeftBracketToken = 0,
|
||||
@ -1053,8 +1126,8 @@ private:
|
||||
#undef N16
|
||||
//!@endcond
|
||||
|
||||
if (sizeof(Ch) == 1 || unsigned(c) < 256)
|
||||
return (Token)tokenMap[(unsigned char)c];
|
||||
if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
|
||||
return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
|
||||
else
|
||||
return NumberToken;
|
||||
}
|
||||
@ -1220,7 +1293,7 @@ private:
|
||||
}
|
||||
}; // End of G
|
||||
|
||||
return (IterativeParsingState)G[state][token];
|
||||
return static_cast<IterativeParsingState>(G[state][token]);
|
||||
}
|
||||
|
||||
// Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
|
||||
@ -1375,14 +1448,14 @@ private:
|
||||
}
|
||||
|
||||
switch (src) {
|
||||
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
|
||||
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
|
||||
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
|
||||
case IterativeParsingObjectInitialState:
|
||||
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
|
||||
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
|
||||
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
|
||||
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,7 +1465,8 @@ private:
|
||||
ClearStackOnExit scope(*this);
|
||||
IterativeParsingState state = IterativeParsingStartState;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
while (is.Peek() != '\0') {
|
||||
Token t = Tokenize(is.Peek());
|
||||
IterativeParsingState n = Predict(state, t);
|
||||
@ -1409,7 +1483,8 @@ private:
|
||||
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
||||
break;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
}
|
||||
|
||||
// Handle the end of file.
|
||||
@ -1429,6 +1504,11 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -23,15 +23,16 @@
|
||||
#include "stringbuffer.h"
|
||||
#include <new> // placement new
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! JSON writer
|
||||
@ -205,7 +206,7 @@ protected:
|
||||
char buffer[11];
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -213,7 +214,7 @@ protected:
|
||||
char buffer[10];
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -221,7 +222,7 @@ protected:
|
||||
char buffer[21];
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ protected:
|
||||
char buffer[20];
|
||||
char* end = internal::u64toa(u64, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -237,12 +238,12 @@ protected:
|
||||
char buffer[25];
|
||||
char* end = internal::dtoa(d, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
@ -259,7 +260,7 @@ protected:
|
||||
GenericStringStream<SourceEncoding> is(str);
|
||||
while (is.Tell() < length) {
|
||||
const Ch c = is.Peek();
|
||||
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
|
||||
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
|
||||
// Unicode escaping
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
@ -290,15 +291,15 @@ protected:
|
||||
os_->Put(hexDigits[(trail ) & 15]);
|
||||
}
|
||||
}
|
||||
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
|
||||
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && escape[static_cast<unsigned char>(c)]) {
|
||||
is.Take();
|
||||
os_->Put('\\');
|
||||
os_->Put(escape[(unsigned char)c]);
|
||||
if (escape[(unsigned char)c] == 'u') {
|
||||
os_->Put(static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
|
||||
if (escape[static_cast<unsigned char>(c)] == 'u') {
|
||||
os_->Put('0');
|
||||
os_->Put('0');
|
||||
os_->Put(hexDigits[(unsigned char)c >> 4]);
|
||||
os_->Put(hexDigits[(unsigned char)c & 0xF]);
|
||||
os_->Put(hexDigits[static_cast<unsigned char>(c) >> 4]);
|
||||
os_->Put(hexDigits[static_cast<unsigned char>(c) & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -350,7 +351,7 @@ template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt(int i) {
|
||||
char *buffer = os_->Push(11);
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
os_->Pop(11 - (end - buffer));
|
||||
os_->Pop(static_cast<size_t>(11 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -358,7 +359,7 @@ template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
|
||||
char *buffer = os_->Push(10);
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
os_->Pop(10 - (end - buffer));
|
||||
os_->Pop(static_cast<size_t>(10 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -366,7 +367,7 @@ template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
|
||||
char *buffer = os_->Push(21);
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
os_->Pop(21 - (end - buffer));
|
||||
os_->Pop(static_cast<size_t>(21 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -374,7 +375,7 @@ template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
|
||||
char *buffer = os_->Push(20);
|
||||
const char* end = internal::u64toa(u, buffer);
|
||||
os_->Pop(20 - (end - buffer));
|
||||
os_->Pop(static_cast<size_t>(20 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -382,7 +383,7 @@ template<>
|
||||
inline bool Writer<StringBuffer>::WriteDouble(double d) {
|
||||
char *buffer = os_->Push(25);
|
||||
char* end = internal::dtoa(d, buffer);
|
||||
os_->Pop(25 - (end - buffer));
|
||||
os_->Pop(static_cast<size_t>(25 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -392,4 +393,8 @@ RAPIDJSON_NAMESPACE_END
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
|
12
library.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "RapidJSON",
|
||||
"keywords": "json, sax, dom, parser, generator",
|
||||
"description": "A fast JSON parser/generator for C++ with both SAX/DOM style API",
|
||||
"include": "include",
|
||||
"examples": "example/*/*.cpp",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/miloyip/rapidjson"
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ Tencent is pleased to support the open source community by making RapidJSON avai
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
75
rapidjson.autopkg
Normal file
@ -0,0 +1,75 @@
|
||||
nuget {
|
||||
//Usage: Write-NuGetPackage rapidjson.autopkg -defines:MYVERSION=1.0.2
|
||||
//Be sure you are running Powershell 3.0 and have the CoApp powershell extensions installed properly.
|
||||
nuspec {
|
||||
id = rapidjson;
|
||||
version : ${MYVERSION};
|
||||
title: "rapidjson";
|
||||
authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.0.2"};
|
||||
owners: {"@lsantos (github)"};
|
||||
licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt";
|
||||
projectUrl: "https://github.com/miloyip/rapidjson/";
|
||||
iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png";
|
||||
requireLicenseAcceptance:false;
|
||||
summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API";
|
||||
|
||||
// if you need to span several lines you can prefix a string with an @ symbol (exactly like c# does).
|
||||
description: @"Rapidjson is an attempt to create the fastest JSON parser and generator.
|
||||
|
||||
- Small but complete. Supports both SAX and DOM style API. SAX parser only a few hundred lines of code.
|
||||
- Fast. In the order of magnitude of strlen(). Optionally supports SSE2/SSE4.2 for acceleration.
|
||||
- Self-contained. Minimal dependency on standard libraries. No BOOST, not even STL.
|
||||
- Compact. Each JSON value is 16 or 20 bytes for 32 or 64-bit machines respectively (excluding text string storage). With the custom memory allocator, parser allocates memory compactly during parsing.
|
||||
- Full RFC4627 compliance. Supports UTF-8, UTF-16 and UTF-32.
|
||||
- Support both in-situ parsing (directly decode strings into the source JSON text) and non-destructive parsing (decode strings into new buffers).
|
||||
- Parse number to int/unsigned/int64_t/uint64_t/double depending on input
|
||||
- Support custom memory allocation. Also, the default memory pool allocator can also be supplied with a user buffer (such as a buffer allocated on user's heap or - programme stack) to minimize allocation.
|
||||
|
||||
As the name implies, rapidjson is inspired by rapidxml.";
|
||||
|
||||
releaseNotes: @"
|
||||
Added
|
||||
Add Value::XXXMember(...) overloads for std::string (#335)
|
||||
|
||||
Fixed
|
||||
Include rapidjson.h for all internal/error headers.
|
||||
Parsing some numbers incorrectly in full-precision mode (kFullPrecisionParseFlag) (#342)
|
||||
Fix alignment of 64bit platforms (#328)
|
||||
Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502)
|
||||
|
||||
Changed
|
||||
CMakeLists for include as a thirdparty in projects (#334, #337)
|
||||
Change Document::ParseStream() to use stack allocator for Reader (ffbe386)";
|
||||
|
||||
copyright: "Copyright 2015";
|
||||
tags: { native, coapp, JSON, nativepackage };
|
||||
language: en-US;
|
||||
};
|
||||
|
||||
dependencies {
|
||||
packages : {
|
||||
//TODO: Add dependecies here in [pkg.name]/[version] form per newline
|
||||
//zlib/[1.2.8],
|
||||
};
|
||||
}
|
||||
|
||||
// the files that go into the content folders
|
||||
files {
|
||||
#defines {
|
||||
SDK_ROOT = .\;
|
||||
}
|
||||
|
||||
// grab all the files in the include folder
|
||||
// the folder that contains all the .h files will
|
||||
// automatically get added to the Includes path.
|
||||
nestedinclude += {
|
||||
#destination = ${d_include}rapidjson;
|
||||
"${SDK_ROOT}include\rapidjson\**\*.h"
|
||||
};
|
||||
};
|
||||
|
||||
targets {
|
||||
// We're trying to be standard about these sorts of thing. (Will help with config.h later :D)
|
||||
//Defines += HAS_EQCORE;
|
||||
};
|
||||
}
|
17
readme.md
@ -1,4 +1,7 @@
|
||||

|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
@ -7,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
|
||||
|
||||
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
|
||||
* RapidJSON Documentation
|
||||
* [English](http://miloyip.github.io/rapidjson/)
|
||||
* [简体中文](http://miloyip.github.io/rapidjson/zh-cn/)
|
||||
* [English](http://rapidjson.org/)
|
||||
* [简体中文](http://rapidjson.org/zh-cn/)
|
||||
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
|
||||
|
||||
## Build status
|
||||
@ -28,15 +31,15 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
|
||||
|
||||
RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/).
|
||||
|
||||
* 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.2 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** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL.
|
||||
|
||||
* RapidJSON is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
|
||||
* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
|
||||
|
||||
* RapidJSON is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
|
||||
* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
|
||||
|
||||
More features can be read [here](doc/features.md).
|
||||
|
||||
|
@ -1,13 +1,17 @@
|
||||

|
||||
|
||||

|
||||
|
||||
## 高效的C++ JSON解析/生成器,提供SAX及DOM风格API
|
||||
|
||||
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.
|
||||
|
||||
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
|
||||
* RapidJSON 文档
|
||||
* [English](http://miloyip.github.io/rapidjson/)
|
||||
* [简体中文](http://miloyip.github.io/rapidjson/zh-cn/)
|
||||
* [English](http://rapidjson.org/)
|
||||
* [简体中文](http://rapidjson.org/zh-cn/)
|
||||
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/)可下载PDF/EPUB/MOBI,但不含API参考手册。
|
||||
|
||||
## Build 状态
|
||||
@ -58,21 +62,21 @@ RapidJSON是跨平台的。以下是一些曾测试的平台/编译器组合
|
||||
|
||||
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)。
|
||||
2. 下载 [premake4](http://industriousone.com/premake/download)。
|
||||
3. 复制 premake4 可执行文件至 `rapidjson/build` (或系统路径)。
|
||||
4. 进入`rapidjson/build/`目录,在Windows下执行`premake.bat`,在Linux或其他平台下执行`premake.sh`。
|
||||
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`目录。
|
||||
2. 在rapidjson目渌下,建立一个`build`目录。
|
||||
3. 在`build`目录下执行`cmake ..`命令以设置生成。Windows用户可使用cmake-gui应用程序。
|
||||
4. 在Windows下,编译生成在build目录中的solution。在Linux下,于build目录运行`make`。
|
||||
|
||||
生成[Doxygen](http://doxygen.org)文档的步骤:
|
||||
成功生成后,你会在`bin`的目录下找到编译后的测试及例子可执行文件。而生成的文档将位于build下的`doc/html`目录。要执行测试,请在build下执行`make test`或`ctest`。使用`ctest -V`命令可获取详细的输出。
|
||||
|
||||
1. 下载及安装[Doxygen](http://doxygen.org/download.html)。
|
||||
2. 在顶层目录执行`doxygen build/Doxyfile`。
|
||||
3. 在`doc/html`浏览文档。
|
||||
我们也可以把程序库安装至全系统中,只要在具管理權限下从build目录执行`make install`命令。这样会按系统的偏好设置安装所有文件。当安装RapidJSON后,其他的CMake项目需要使用它时,可以通过在`CMakeLists.txt`加入一句`find_package(RapidJSON)`。
|
||||
|
||||
## 用法一览
|
||||
|
||||
|
@ -9,7 +9,7 @@ IF(GTESTSRC_FOUND)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${GTEST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/googletest)
|
||||
include_directories(${GTEST_INCLUDE_DIR})
|
||||
include_directories(SYSTEM ${GTEST_INCLUDE_DIR})
|
||||
|
||||
set(TEST_LIBRARIES gtest gtest_main)
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 "perftest.h"
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 "perftest.h"
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 PERFTEST_H_
|
||||
#define PERFTEST_H_
|
||||
@ -71,9 +65,20 @@ public:
|
||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename_ = "../../bin/data/sample.json", "rb");
|
||||
|
||||
const char *paths[] = {
|
||||
"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);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 "perftest.h"
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 "perftest.h"
|
||||
|
||||
@ -304,11 +298,28 @@ TEST_F(RapidJson, internal_Pow10) {
|
||||
EXPECT_GT(sum, 0.0);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) {
|
||||
TEST_F(RapidJson, SkipWhitespace_Basic) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
ASSERT_TRUE(doc.Parse(whitespace_).IsArray());
|
||||
}
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||
s.Take();
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(SkipWhitespace)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
rapidjson::SkipWhitespace(s);
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SkipWhitespace_strspn) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
const char* s = whitespace_ + std::strspn(whitespace_, " \t\r\n");
|
||||
ASSERT_EQ('[', *s);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, UTF8_Validate) {
|
||||
|
@ -8,6 +8,7 @@ set(UNITTEST_SOURCES
|
||||
itoatest.cpp
|
||||
jsoncheckertest.cpp
|
||||
namespacetest.cpp
|
||||
pointertest.cpp
|
||||
prettywritertest.cpp
|
||||
readertest.cpp
|
||||
simdtest.cpp
|
||||
@ -20,11 +21,13 @@ set(UNITTEST_SOURCES
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DRAPIDJSON_HAS_STDSTRING=1")
|
||||
|
||||
add_library(namespacetest STATIC namespacetest.cpp)
|
||||
|
||||
add_executable(unittest ${UNITTEST_SOURCES})
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
@ -26,26 +20,31 @@ using namespace rapidjson;
|
||||
|
||||
template <typename Allocator>
|
||||
void TestAllocator(Allocator& a) {
|
||||
uint8_t* p = (uint8_t*)a.Malloc(100);
|
||||
EXPECT_TRUE(a.Malloc(0) == 0);
|
||||
|
||||
uint8_t* p = static_cast<uint8_t*>(a.Malloc(100));
|
||||
EXPECT_TRUE(p != 0);
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
p[i] = (uint8_t)i;
|
||||
p[i] = static_cast<uint8_t>(i);
|
||||
|
||||
// Expand
|
||||
uint8_t* q = (uint8_t*)a.Realloc(p, 100, 200);
|
||||
uint8_t* q = static_cast<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;
|
||||
q[i] = static_cast<uint8_t>(i);
|
||||
|
||||
// Shrink
|
||||
uint8_t *r = (uint8_t*)a.Realloc(q, 200, 150);
|
||||
uint8_t *r = static_cast<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);
|
||||
|
||||
// Realloc to zero size
|
||||
EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
|
||||
}
|
||||
|
||||
TEST(Allocator, CrtAllocator) {
|
||||
@ -57,8 +56,28 @@ TEST(Allocator, MemoryPoolAllocator) {
|
||||
MemoryPoolAllocator<> a;
|
||||
TestAllocator(a);
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
EXPECT_TRUE(a.Malloc(i) != 0);
|
||||
EXPECT_LE(a.Size(), a.Capacity());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Allocator, Alignment) {
|
||||
#if RAPIDJSON_64BIT == 1
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0));
|
||||
for (uint64_t i = 1; i < 8; i++) {
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i));
|
||||
}
|
||||
#else
|
||||
EXPECT_EQ(0u, RAPIDJSON_ALIGN(0u));
|
||||
for (uint32_t i = 1; i < 4; i++) {
|
||||
EXPECT_EQ(4u, RAPIDJSON_ALIGN(i));
|
||||
EXPECT_EQ(8u, RAPIDJSON_ALIGN(4u + i));
|
||||
EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF4u + i));
|
||||
EXPECT_EQ(0xFFFFFFFCu, RAPIDJSON_ALIGN(0xFFFFFFF8u + i));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/document.h"
|
||||
@ -25,6 +19,7 @@
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
@ -33,6 +28,7 @@ void ParseCheck(DocumentType& doc) {
|
||||
typedef typename DocumentType::ValueType ValueType;
|
||||
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_TRUE(static_cast<ParseResult>(doc));
|
||||
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
|
||||
@ -67,8 +63,8 @@ void ParseCheck(DocumentType& doc) {
|
||||
const ValueType& a = doc["a"];
|
||||
EXPECT_TRUE(a.IsArray());
|
||||
EXPECT_EQ(4u, a.Size());
|
||||
for (SizeType i = 0; i < 4; i++)
|
||||
EXPECT_EQ(i + 1, a[i].GetUint());
|
||||
for (SizeType j = 0; j < 4; j++)
|
||||
EXPECT_EQ(j + 1, a[j].GetUint());
|
||||
}
|
||||
|
||||
template <typename Allocator, typename StackAllocator>
|
||||
@ -100,17 +96,37 @@ TEST(Document, Parse) {
|
||||
ParseTest<CrtAllocator, CrtAllocator>();
|
||||
}
|
||||
|
||||
TEST(Document, UnchangedOnParseError) {
|
||||
Document doc;
|
||||
doc.SetArray().PushBack(0, doc.GetAllocator());
|
||||
|
||||
ParseResult err = doc.Parse("{]");
|
||||
EXPECT_TRUE(doc.HasParseError());
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsArray());
|
||||
EXPECT_EQ(doc.Size(), 1u);
|
||||
|
||||
err = doc.Parse("{}");
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_FALSE(err.IsError());
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
EXPECT_EQ(doc.MemberCount(), 0u);
|
||||
}
|
||||
|
||||
static FILE* OpenEncodedFile(const char* filename) {
|
||||
const char *paths[] = {
|
||||
"encodings/%s",
|
||||
"bin/encodings/%s",
|
||||
"../bin/encodings/%s",
|
||||
"../../bin/encodings/%s",
|
||||
"../../../bin/encodings/%s"
|
||||
"encodings",
|
||||
"bin/encodings",
|
||||
"../bin/encodings",
|
||||
"../../bin/encodings",
|
||||
"../../../bin/encodings"
|
||||
};
|
||||
char buffer[1024];
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, paths[i], filename);
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
FILE *fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
return fp;
|
||||
@ -141,21 +157,22 @@ TEST(Document, ParseStream_EncodedInputStream) {
|
||||
StringBuffer bos;
|
||||
typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
|
||||
OutputStream eos(bos, false); // Not writing BOM
|
||||
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
|
||||
d.Accept(writer);
|
||||
|
||||
{
|
||||
// Condense the original file and compare.
|
||||
FILE *fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer(bos2);
|
||||
reader.Parse(is, writer);
|
||||
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
|
||||
d.Accept(writer);
|
||||
}
|
||||
|
||||
// Condense the original file and compare.
|
||||
fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer2(bos2);
|
||||
reader.Parse(is, writer2);
|
||||
fclose(fp);
|
||||
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
}
|
||||
|
||||
TEST(Document, ParseStream_AutoUTFInputStream) {
|
||||
@ -182,18 +199,17 @@ TEST(Document, ParseStream_AutoUTFInputStream) {
|
||||
Writer<StringBuffer> writer(bos);
|
||||
d.Accept(writer);
|
||||
|
||||
{
|
||||
// Condense the original file and compare.
|
||||
FILE *fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer(bos2);
|
||||
reader.Parse(is, writer);
|
||||
// Condense the original file and compare.
|
||||
fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer2(bos2);
|
||||
reader.Parse(is, writer2);
|
||||
fclose(fp);
|
||||
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
}
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
}
|
||||
|
||||
TEST(Document, Swap) {
|
||||
@ -206,7 +222,8 @@ TEST(Document, Swap) {
|
||||
o.SetObject().AddMember("a", 1, a);
|
||||
|
||||
// Swap between Document and Value
|
||||
d1.Swap(o);
|
||||
// d1.Swap(o); // doesn't compile
|
||||
o.Swap(d1);
|
||||
EXPECT_TRUE(d1.IsObject());
|
||||
EXPECT_TRUE(o.IsArray());
|
||||
|
||||
@ -216,18 +233,44 @@ TEST(Document, Swap) {
|
||||
d1.Swap(d2);
|
||||
EXPECT_TRUE(d1.IsArray());
|
||||
EXPECT_TRUE(d2.IsObject());
|
||||
EXPECT_EQ(&d2.GetAllocator(), &a);
|
||||
|
||||
// reset value
|
||||
Value().Swap(d1);
|
||||
EXPECT_TRUE(d1.IsNull());
|
||||
|
||||
// reset document, including allocator
|
||||
Document().Swap(d2);
|
||||
EXPECT_TRUE(d2.IsNull());
|
||||
EXPECT_NE(&d2.GetAllocator(), &a);
|
||||
|
||||
// testing std::swap compatibility
|
||||
d1.SetBool(true);
|
||||
using std::swap;
|
||||
swap(d1, d2);
|
||||
EXPECT_TRUE(d1.IsNull());
|
||||
EXPECT_TRUE(d2.IsTrue());
|
||||
|
||||
swap(o, d2);
|
||||
EXPECT_TRUE(o.IsTrue());
|
||||
EXPECT_TRUE(d2.IsArray());
|
||||
}
|
||||
|
||||
|
||||
// This should be slow due to assignment in inner-loop.
|
||||
struct OutputStringStream : public std::ostringstream {
|
||||
typedef char Ch;
|
||||
|
||||
virtual ~OutputStringStream();
|
||||
|
||||
void Put(char c) {
|
||||
put(c);
|
||||
}
|
||||
void Flush() {}
|
||||
};
|
||||
|
||||
OutputStringStream::~OutputStringStream() {}
|
||||
|
||||
TEST(Document, AcceptWriter) {
|
||||
Document doc;
|
||||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
@ -245,7 +288,7 @@ TEST(Document, UserBuffer) {
|
||||
char parseBuffer[1024];
|
||||
MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
|
||||
MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
|
||||
DocumentType doc(&valueAllocator, sizeof(parseBuffer), &parseAllocator);
|
||||
DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
|
||||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
|
||||
@ -280,7 +323,7 @@ TEST(Document, UTF16_Document) {
|
||||
GenericValue< UTF16<> >& s = v[L"created_at"];
|
||||
ASSERT_TRUE(s.IsString());
|
||||
|
||||
EXPECT_EQ(0, wcscmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString()));
|
||||
EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
@ -346,7 +389,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) {
|
||||
EXPECT_TRUE(a.IsNull());
|
||||
EXPECT_TRUE(b.IsArray());
|
||||
EXPECT_EQ(3u, b.Size());
|
||||
EXPECT_EQ(&a.GetAllocator(), (void*)0);
|
||||
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||
|
||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||
@ -359,7 +402,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) {
|
||||
EXPECT_TRUE(b.IsNull());
|
||||
EXPECT_TRUE(c.IsObject());
|
||||
EXPECT_EQ(2u, c.MemberCount());
|
||||
EXPECT_EQ(&b.GetAllocator(), (void*)0);
|
||||
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||
}
|
||||
|
||||
@ -440,7 +483,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) {
|
||||
EXPECT_TRUE(a.IsNull());
|
||||
EXPECT_TRUE(b.IsArray());
|
||||
EXPECT_EQ(3u, b.Size());
|
||||
EXPECT_EQ(&a.GetAllocator(), (void*)0);
|
||||
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||
|
||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||
@ -454,7 +497,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) {
|
||||
EXPECT_TRUE(b.IsNull());
|
||||
EXPECT_TRUE(c.IsObject());
|
||||
EXPECT_EQ(2u, c.MemberCount());
|
||||
EXPECT_EQ(&b.GetAllocator(), (void*)0);
|
||||
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/filereadstream.h"
|
||||
@ -31,6 +25,7 @@ using namespace rapidjson;
|
||||
class EncodedStreamTest : public ::testing::Test {
|
||||
public:
|
||||
EncodedStreamTest() : json_(), length_() {}
|
||||
virtual ~EncodedStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
json_ = ReadFile("utf8.json", true, &length_);
|
||||
@ -48,15 +43,15 @@ private:
|
||||
protected:
|
||||
static FILE* Open(const char* filename) {
|
||||
const char *paths[] = {
|
||||
"encodings/%s",
|
||||
"bin/encodings/%s",
|
||||
"../bin/encodings/%s",
|
||||
"../../bin/encodings/%s",
|
||||
"../../../bin/encodings/%s"
|
||||
"encodings",
|
||||
"bin/encodings",
|
||||
"../bin/encodings",
|
||||
"../../bin/encodings",
|
||||
"../../../bin/encodings"
|
||||
};
|
||||
char buffer[1024];
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, paths[i], filename);
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
FILE *fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
return fp;
|
||||
@ -73,9 +68,9 @@ protected:
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*outLength = (size_t)ftell(fp);
|
||||
*outLength = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* buffer = (char*)malloc(*outLength + 1);
|
||||
char* buffer = static_cast<char*>(malloc(*outLength + 1));
|
||||
size_t readLength = fread(buffer, 1, *outLength, fp);
|
||||
buffer[readLength] = '\0';
|
||||
fclose(fp);
|
||||
@ -254,6 +249,8 @@ protected:
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
EncodedStreamTest::~EncodedStreamTest() {}
|
||||
|
||||
TEST_F(EncodedStreamTest, EncodedInputStream) {
|
||||
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8.json");
|
||||
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/filereadstream.h"
|
||||
@ -246,7 +240,6 @@ static const unsigned kCodepointRanges[] = {
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
#define UTF8_ACCEPT 0u
|
||||
#define UTF8_REJECT 12u
|
||||
|
||||
static const unsigned char utf8d[] = {
|
||||
// The first part of the table maps bytes to character classes that
|
||||
@ -304,7 +297,7 @@ TEST(EncodingsTest, UTF8) {
|
||||
|
||||
unsigned decodedCount = 0;
|
||||
for (const char* s = encodedStr; *s; ++s)
|
||||
if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) {
|
||||
if (!decode(&state, &decodedCodepoint, static_cast<unsigned char>(*s))) {
|
||||
EXPECT_EQ(codepoint, decodedCodepoint);
|
||||
decodedCount++;
|
||||
}
|
||||
@ -361,7 +354,7 @@ TEST(EncodingsTest, UTF16) {
|
||||
unsigned state = 0;
|
||||
UTF16<>::Ch buffer[3], *p = &buffer[0];
|
||||
for (const char* s = utf8os.GetString(); *s; ++s) {
|
||||
if (!decode(&state, &decodedCodepoint, (unsigned char)*s))
|
||||
if (!decode(&state, &decodedCodepoint, static_cast<unsigned char>(*s)))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/filereadstream.h"
|
||||
@ -28,6 +22,7 @@ using namespace rapidjson;
|
||||
class FileStreamTest : public ::testing::Test {
|
||||
public:
|
||||
FileStreamTest() : filename_(), json_(), length_() {}
|
||||
virtual ~FileStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
const char *paths[] = {
|
||||
@ -48,9 +43,9 @@ public:
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
length_ = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
json_ = static_cast<char*>(malloc(length_ + 1));
|
||||
size_t readLength = fread(json_, 1, length_, fp);
|
||||
json_[readLength] = '\0';
|
||||
fclose(fp);
|
||||
@ -71,6 +66,8 @@ protected:
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
FileStreamTest::~FileStreamTest() {}
|
||||
|
||||
TEST_F(FileStreamTest, FileReadStream) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
@ -36,28 +30,28 @@ template <>
|
||||
struct Traits<uint32_t> {
|
||||
enum { kBufferSize = 11 };
|
||||
enum { kMaxDigit = 10 };
|
||||
static uint32_t Negate(uint32_t x) { return x; };
|
||||
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; };
|
||||
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; };
|
||||
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; };
|
||||
static int64_t Negate(int64_t x) { return -x; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
@ -26,16 +20,16 @@ using namespace rapidjson;
|
||||
|
||||
static char* ReadFile(const char* filename, size_t& length) {
|
||||
const char *paths[] = {
|
||||
"jsonchecker/%s",
|
||||
"bin/jsonchecker/%s",
|
||||
"../bin/jsonchecker/%s",
|
||||
"../../bin/jsonchecker/%s",
|
||||
"../../../bin/jsonchecker/%s"
|
||||
"jsonchecker",
|
||||
"bin/jsonchecker",
|
||||
"../bin/jsonchecker",
|
||||
"../../bin/jsonchecker",
|
||||
"../../../bin/jsonchecker"
|
||||
};
|
||||
char buffer[1024];
|
||||
FILE *fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, paths[i], filename);
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
break;
|
||||
@ -45,9 +39,9 @@ static char* ReadFile(const char* filename, size_t& length) {
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length = (size_t)ftell(fp);
|
||||
length = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = (char*)malloc(length + 1);
|
||||
char* json = static_cast<char*>(malloc(length + 1));
|
||||
size_t readLength = fread(json, 1, length, fp);
|
||||
json[readLength] = '\0';
|
||||
fclose(fp);
|
||||
@ -74,10 +68,10 @@ TEST(JsonChecker, Reader) {
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
document.Parse((const char*)json);
|
||||
document.Parse(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>((const char*)json);
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
@ -94,10 +88,10 @@ TEST(JsonChecker, Reader) {
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
document.Parse((const char*)json);
|
||||
document.Parse(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>((const char*)json);
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
|
1493
test/unittest/pointertest.cpp
Normal 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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
@ -155,13 +149,13 @@ TEST(PrettyWriter, FileWriteStream) {
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t size = (size_t)ftell(fp);
|
||||
size_t size = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = (char*)malloc(size + 1);
|
||||
char* json = static_cast<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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
@ -31,6 +25,12 @@ using namespace rapidjson;
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
RAPIDJSON_DIAG_OFF(float-equal)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(variadic-macros)
|
||||
#endif
|
||||
|
||||
template<bool expect>
|
||||
@ -165,12 +165,12 @@ TEST(Reader, ParseNumber_Integer) {
|
||||
u.u |= r();
|
||||
|
||||
char buffer[32];
|
||||
if (u.u >= 4294967296ULL) {
|
||||
if (u.u > uint64_t(4294967295u)) {
|
||||
*internal::u64toa(u.u, buffer) = '\0';
|
||||
TEST_INTEGER(ParseUint64Handler, buffer, u.u);
|
||||
}
|
||||
|
||||
if (u.i <= -2147483649LL) {
|
||||
if (u.i < -int64_t(2147483648u)) {
|
||||
*internal::i64toa(u.i, buffer) = '\0';
|
||||
TEST_INTEGER(ParseInt64Handler, buffer, u.i);
|
||||
}
|
||||
@ -199,7 +199,7 @@ static void TestParseDouble() {
|
||||
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
|
||||
TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289
|
||||
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
|
||||
@ -225,13 +225,19 @@ static void TestParseDouble() {
|
||||
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, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double
|
||||
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, "-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, "123e34", 123e34); // Fast Path Cases In Disguise
|
||||
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, "-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, "123e34", 123e34); // Fast Path Cases In Disguise
|
||||
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, "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
|
||||
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
|
||||
@ -327,15 +333,44 @@ static void TestParseDouble() {
|
||||
if (fullPrecision) {
|
||||
EXPECT_EQ(d.Uint64Value(), a.Uint64Value());
|
||||
if (d.Uint64Value() != a.Uint64Value())
|
||||
printf(" String: %sn Actual: %.17gnExpected: %.17gn", buffer, h.actual_, d.Value());
|
||||
printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value());
|
||||
}
|
||||
else {
|
||||
EXPECT_EQ(d.Sign(), a.Sign()); /* for 0.0 != -0.0 */
|
||||
EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0
|
||||
EXPECT_DOUBLE_EQ(d.Value(), h.actual_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #340
|
||||
TEST_DOUBLE(fullPrecision, "7.450580596923828e-9", 7.450580596923828e-9);
|
||||
{
|
||||
internal::Double d(1.0);
|
||||
for (int i = 0; i < 324; i++) {
|
||||
char buffer[32];
|
||||
*internal::dtoa(d.Value(), buffer) = '\0';
|
||||
|
||||
StringStream s(buffer);
|
||||
ParseDoubleHandler h;
|
||||
Reader reader;
|
||||
ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code());
|
||||
EXPECT_EQ(1u, h.step_);
|
||||
internal::Double a(h.actual_);
|
||||
if (fullPrecision) {
|
||||
EXPECT_EQ(d.Uint64Value(), a.Uint64Value());
|
||||
if (d.Uint64Value() != a.Uint64Value())
|
||||
printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value());
|
||||
}
|
||||
else {
|
||||
EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0
|
||||
EXPECT_DOUBLE_EQ(d.Value(), h.actual_);
|
||||
}
|
||||
|
||||
|
||||
d = d.Value() * 0.5;
|
||||
}
|
||||
}
|
||||
#undef TEST_DOUBLE
|
||||
}
|
||||
|
||||
@ -427,7 +462,7 @@ struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod
|
||||
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
||||
EXPECT_EQ(0, str_);
|
||||
if (copy) {
|
||||
str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch));
|
||||
str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch)));
|
||||
memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch));
|
||||
}
|
||||
else
|
||||
@ -610,11 +645,11 @@ TEST(Reader, ParseString_Error) {
|
||||
{
|
||||
char e[] = { '[', '\"', 0, '\"', ']', '\0' };
|
||||
for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
|
||||
e[2] = c;
|
||||
e[2] = static_cast<char>(c);
|
||||
ParseErrorCode error = TestString<UTF8<> >(e);
|
||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
|
||||
if (error != kParseErrorStringInvalidEncoding)
|
||||
std::cout << (unsigned)(unsigned char)c << std::endl;
|
||||
std::cout << static_cast<unsigned>(c) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,7 +657,7 @@ TEST(Reader, ParseString_Error) {
|
||||
{
|
||||
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
|
||||
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
|
||||
e[2] = (char)c;
|
||||
e[2] = static_cast<char>(c);
|
||||
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e);
|
||||
}
|
||||
}
|
||||
@ -742,7 +777,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
|
||||
default: ADD_FAILURE(); return false;
|
||||
}
|
||||
}
|
||||
bool Uint(unsigned i) { return Int(i); }
|
||||
bool Uint(unsigned i) { return Int(static_cast<int>(i)); }
|
||||
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) {
|
||||
switch(step_) {
|
||||
@ -995,15 +1030,15 @@ public:
|
||||
|
||||
Ch Peek() const {
|
||||
int c = is_.peek();
|
||||
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
|
||||
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
Ch Take() {
|
||||
int c = is_.get();
|
||||
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
|
||||
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
size_t Tell() const { return (size_t)is_.tellg(); }
|
||||
size_t Tell() const { return static_cast<size_t>(is_.tellg()); }
|
||||
|
||||
Ch* PutBegin() { assert(false); return 0; }
|
||||
void Put(Ch) { assert(false); }
|
||||
@ -1114,7 +1149,7 @@ struct IterativeParsingReaderHandler {
|
||||
bool EndObject(SizeType c) {
|
||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||
Logs[LogCount++] = LOG_ENDOBJECT;
|
||||
Logs[LogCount++] = (int)c;
|
||||
Logs[LogCount++] = static_cast<int>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1123,7 +1158,7 @@ struct IterativeParsingReaderHandler {
|
||||
bool EndArray(SizeType c) {
|
||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||
Logs[LogCount++] = LOG_ENDARRAY;
|
||||
Logs[LogCount++] = (int)c;
|
||||
Logs[LogCount++] = static_cast<int>(c);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -1320,6 +1355,113 @@ TEST(Reader, ParseTerminationByHandler) {
|
||||
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
|
||||
}
|
||||
|
||||
TEST(Reader, ParseComments) {
|
||||
const char* json =
|
||||
"// Here is a one-line comment.\n"
|
||||
"{// And here's another one\n"
|
||||
" /*And here's an in-line one.*/\"hello\" : \"world\","
|
||||
" \"t\" :/* And one with '*' symbol*/true ,"
|
||||
"/* A multiline comment\n"
|
||||
" goes here*/"
|
||||
" \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]"
|
||||
"}/*And the last one to be sure */";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(20u, h.step_);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseEmptyInlineComment) {
|
||||
const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(20u, h.step_);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseEmptyOnelineComment) {
|
||||
const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(20u, h.step_);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseMultipleCommentsInARow) {
|
||||
const char* json =
|
||||
"{/* first comment *//* second */\n"
|
||||
"/* third */ /*fourth*/// last one\n"
|
||||
"\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(20u, h.step_);
|
||||
}
|
||||
|
||||
TEST(Reader, InlineCommentsAreDisabledByDefault) {
|
||||
{
|
||||
const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||
}
|
||||
|
||||
{
|
||||
const char* json =
|
||||
"{\"hello\" : /* Multiline comment starts here\n"
|
||||
" continues here\n"
|
||||
" and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Reader, OnelineCommentsAreDisabledByDefault) {
|
||||
const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
|
||||
}
|
||||
|
||||
TEST(Reader, EofAfterOneLineComment) {
|
||||
const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode());
|
||||
}
|
||||
|
||||
TEST(Reader, IncompleteMultilineComment) {
|
||||
const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}";
|
||||
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
|
||||
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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
|
||||
@ -47,7 +41,7 @@ using namespace rapidjson_simd;
|
||||
|
||||
template <typename StreamType>
|
||||
void TestSkipWhitespace() {
|
||||
for (int step = 1; step < 32; step++) {
|
||||
for (size_t step = 1; step < 32; step++) {
|
||||
char buffer[1025];
|
||||
for (size_t i = 0; i < 1024; i++)
|
||||
buffer[i] = " \t\r\n"[i % 4];
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/stringbuffer.h"
|
||||
|
@ -1,27 +1,26 @@
|
||||
// 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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/strtod.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
@ -105,13 +104,13 @@ TEST(Strtod, CheckApproximationCase) {
|
||||
EXPECT_EQ(49, hS_Exp5);
|
||||
|
||||
BigInteger dS = BIGINTEGER_LITERAL(dInt);
|
||||
dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<size_t>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<size_t>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<size_t>(hS_Exp2);
|
||||
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS);
|
||||
@ -127,3 +126,7 @@ TEST(Strtod, CheckApproximationCase) {
|
||||
|
||||
EXPECT_EQ(-1, delta.Compare(hS));
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -1,29 +1,28 @@
|
||||
// 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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/rapidjson.h"
|
||||
|
||||
AssertException::~AssertException() throw() {}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
#if _MSC_VER
|
||||
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
_CrtMemState memoryState = { 0 };
|
||||
_CrtMemCheckpoint(&memoryState);
|
||||
//_CrtSetBreakAlloc(X);
|
||||
@ -32,7 +31,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
int ret = RUN_ALL_TESTS();
|
||||
|
||||
#if _MSC_VER
|
||||
#ifdef _MSC_VER
|
||||
// Current gtest constantly leak 2 blocks at exit
|
||||
_CrtMemDumpAllObjectsSince(&memoryState);
|
||||
#endif
|
||||
|
@ -1,30 +1,34 @@
|
||||
// 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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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 UNITTEST_H_
|
||||
#define UNITTEST_H_
|
||||
|
||||
|
||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wreserved-id-macro")
|
||||
#pragma GCC diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -47,6 +51,11 @@
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
// All TEST() macro generated this warning, disable globally
|
||||
#pragma GCC diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
template <typename Ch>
|
||||
inline unsigned StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
@ -57,19 +66,19 @@ inline unsigned StrLen(const Ch* s) {
|
||||
template<typename Ch>
|
||||
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
||||
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
|
||||
return (unsigned)*s1 < (unsigned)*s2 ? -1 : (unsigned)*s1 > (unsigned)*s2;
|
||||
return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
|
||||
}
|
||||
|
||||
template <typename Ch>
|
||||
inline Ch* StrDup(const Ch* str) {
|
||||
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
||||
Ch* buffer = (Ch*)malloc(bufferSize);
|
||||
Ch* buffer = static_cast<Ch*>(malloc(bufferSize));
|
||||
memcpy(buffer, str, bufferSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline FILE* TempFile(char *filename) {
|
||||
#if _MSC_VER
|
||||
#ifdef _MSC_VER
|
||||
filename = tmpnam(filename);
|
||||
|
||||
// For Visual Studio, tmpnam() adds a backslash in front. Remove it.
|
||||
@ -86,13 +95,14 @@ inline FILE* TempFile(char *filename) {
|
||||
}
|
||||
|
||||
// Use exception for catching assert
|
||||
#if _MSC_VER
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
class AssertException : public std::logic_error {
|
||||
public:
|
||||
AssertException(const char* w) : std::logic_error(w) {}
|
||||
virtual ~AssertException() throw();
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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/document.h"
|
||||
@ -278,6 +272,12 @@ TEST(Value, Swap) {
|
||||
EXPECT_TRUE(v1.IsObject());
|
||||
EXPECT_TRUE(v2.IsInt());
|
||||
EXPECT_EQ(1234, v2.GetInt());
|
||||
|
||||
// testing std::swap compatibility
|
||||
using std::swap;
|
||||
swap(v1, v2);
|
||||
EXPECT_TRUE(v1.IsInt());
|
||||
EXPECT_TRUE(v2.IsObject());
|
||||
}
|
||||
|
||||
TEST(Value, Null) {
|
||||
@ -448,7 +448,7 @@ TEST(Value, Uint) {
|
||||
|
||||
TEST(Value, Int64) {
|
||||
// Constructor with int
|
||||
Value x(int64_t(1234LL));
|
||||
Value x(int64_t(1234));
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234, x.GetInt());
|
||||
EXPECT_EQ(1234u, x.GetUint());
|
||||
@ -469,7 +469,7 @@ TEST(Value, Int64) {
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
Value nx(int64_t(-1234LL));
|
||||
Value nx(int64_t(-1234));
|
||||
EXPECT_EQ(-1234, nx.GetInt());
|
||||
EXPECT_EQ(-1234, nx.GetInt64());
|
||||
EXPECT_TRUE(nx.IsInt());
|
||||
@ -482,17 +482,17 @@ TEST(Value, Int64) {
|
||||
z.SetInt64(1234);
|
||||
EXPECT_EQ(1234, z.GetInt64());
|
||||
|
||||
z.SetInt64(2147483648LL); // 2^31, cannot cast as int
|
||||
z.SetInt64(2147483648u); // 2^31, cannot cast as int
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_TRUE(z.IsUint());
|
||||
EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0);
|
||||
|
||||
z.SetInt64(4294967296LL); // 2^32, cannot cast as uint
|
||||
z.SetInt64(int64_t(4294967295u) + 1); // 2^32, cannot cast as uint
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_FALSE(z.IsUint());
|
||||
EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0);
|
||||
|
||||
z.SetInt64(-2147483649LL); // -2^31-1, cannot cast as int
|
||||
z.SetInt64(-int64_t(2147483648u) - 1); // -2^31-1, cannot cast as int
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
|
||||
|
||||
@ -502,7 +502,7 @@ TEST(Value, Int64) {
|
||||
|
||||
TEST(Value, Uint64) {
|
||||
// Constructor with int
|
||||
Value x(uint64_t(1234LL));
|
||||
Value x(uint64_t(1234));
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234, x.GetInt());
|
||||
EXPECT_EQ(1234u, x.GetUint());
|
||||
@ -528,19 +528,19 @@ TEST(Value, Uint64) {
|
||||
z.SetUint64(1234);
|
||||
EXPECT_EQ(1234u, z.GetUint64());
|
||||
|
||||
z.SetUint64(2147483648LL); // 2^31, cannot cast as int
|
||||
z.SetUint64(uint64_t(2147483648u)); // 2^31, cannot cast as int
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_TRUE(z.IsUint());
|
||||
EXPECT_TRUE(z.IsInt64());
|
||||
|
||||
z.SetUint64(4294967296LL); // 2^32, cannot cast as uint
|
||||
z.SetUint64(uint64_t(4294967295u) + 1); // 2^32, cannot cast as uint
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_FALSE(z.IsUint());
|
||||
EXPECT_TRUE(z.IsInt64());
|
||||
|
||||
z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64
|
||||
z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64
|
||||
EXPECT_FALSE(z.IsInt64());
|
||||
EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); // Issue 48
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48
|
||||
EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
|
||||
}
|
||||
|
||||
@ -662,7 +662,7 @@ TEST(Value, String) {
|
||||
// SetString()
|
||||
char s[] = "World";
|
||||
Value w;
|
||||
w.SetString(s, (SizeType)strlen(s), allocator);
|
||||
w.SetString(s, static_cast<SizeType>(strlen(s)), allocator);
|
||||
s[0] = '\0';
|
||||
EXPECT_STREQ("World", w.GetString());
|
||||
EXPECT_EQ(5u, w.GetStringLength());
|
||||
@ -841,23 +841,23 @@ TEST(Value, Array) {
|
||||
EXPECT_EQ(x.Begin(), itr);
|
||||
EXPECT_EQ(9u, x.Size());
|
||||
for (int i = 0; i < 9; i++)
|
||||
EXPECT_EQ(i + 1, x[i][0].GetInt());
|
||||
EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
|
||||
|
||||
// Ease the last
|
||||
itr = x.Erase(x.End() - 1);
|
||||
EXPECT_EQ(x.End(), itr);
|
||||
EXPECT_EQ(8u, x.Size());
|
||||
for (int i = 0; i < 8; i++)
|
||||
EXPECT_EQ(i + 1, x[i][0].GetInt());
|
||||
EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
|
||||
|
||||
// Erase the middle
|
||||
itr = x.Erase(x.Begin() + 4);
|
||||
EXPECT_EQ(x.Begin() + 4, itr);
|
||||
EXPECT_EQ(7u, x.Size());
|
||||
for (int i = 0; i < 4; i++)
|
||||
EXPECT_EQ(i + 1, x[i][0].GetInt());
|
||||
EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
|
||||
for (int i = 4; i < 7; i++)
|
||||
EXPECT_EQ(i + 2, x[i][0].GetInt());
|
||||
EXPECT_EQ(i + 2, x[static_cast<SizeType>(i)][0].GetInt());
|
||||
|
||||
// Erase(ValueIterator, ValueIterator)
|
||||
// Exhaustive test with all 0 <= first < n, first <= last <= n cases
|
||||
@ -879,7 +879,7 @@ TEST(Value, Array) {
|
||||
for (unsigned i = 0; i < first; i++)
|
||||
EXPECT_EQ(i, x[i][0].GetUint());
|
||||
for (unsigned i = first; i < n - removeCount; i++)
|
||||
EXPECT_EQ(i + removeCount, x[i][0].GetUint());
|
||||
EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint());
|
||||
}
|
||||
}
|
||||
|
||||
@ -896,7 +896,7 @@ TEST(Value, Array) {
|
||||
x.Erase(std::remove(x.Begin(), x.End(), null), x.End());
|
||||
EXPECT_EQ(5u, x.Size());
|
||||
for (int i = 0; i < 5; i++)
|
||||
EXPECT_EQ(i * 2, x[i]);
|
||||
EXPECT_EQ(i * 2, x[static_cast<SizeType>(i)]);
|
||||
|
||||
// SetArray()
|
||||
Value z;
|
||||
@ -935,8 +935,8 @@ TEST(Value, Object) {
|
||||
o.AddMember("false", false, allocator);
|
||||
o.AddMember("int", -1, allocator);
|
||||
o.AddMember("uint", 1u, allocator);
|
||||
o.AddMember("int64", INT64_C(-4294967296), allocator);
|
||||
o.AddMember("uint64", UINT64_C(4294967296), allocator);
|
||||
o.AddMember("int64", int64_t(-4294967296), allocator);
|
||||
o.AddMember("uint64", uint64_t(4294967296), allocator);
|
||||
o.AddMember("double", 3.14, allocator);
|
||||
o.AddMember("string", "Jelly", allocator);
|
||||
|
||||
@ -944,8 +944,8 @@ TEST(Value, Object) {
|
||||
EXPECT_FALSE(o["false"].GetBool());
|
||||
EXPECT_EQ(-1, o["int"].GetInt());
|
||||
EXPECT_EQ(1u, o["uint"].GetUint());
|
||||
EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64());
|
||||
EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64());
|
||||
EXPECT_EQ(int64_t(-4294967296), o["int64"].GetInt64());
|
||||
EXPECT_EQ(uint64_t(4294967296), o["uint64"].GetUint64());
|
||||
EXPECT_STREQ("Jelly",o["string"].GetString());
|
||||
EXPECT_EQ(8u, o.MemberCount());
|
||||
}
|
||||
@ -963,6 +963,19 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(2u, o.MemberCount());
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
{
|
||||
// AddMember(StringRefType, const std::string&, Allocator)
|
||||
Value o(kObjectType);
|
||||
o.AddMember("b", std::string("Banana"), allocator);
|
||||
EXPECT_STREQ("Banana", o["b"].GetString());
|
||||
|
||||
// RemoveMember(const std::string&)
|
||||
o.RemoveMember(std::string("b"));
|
||||
EXPECT_TRUE(o.ObjectEmpty());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
// AddMember(GenericValue&&, ...) variants
|
||||
{
|
||||
@ -992,6 +1005,10 @@ TEST(Value, Object) {
|
||||
EXPECT_TRUE(y.HasMember("A"));
|
||||
EXPECT_TRUE(y.HasMember("B"));
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
EXPECT_TRUE(x.HasMember(std::string("A")));
|
||||
#endif
|
||||
|
||||
name.SetString("C\0D");
|
||||
EXPECT_TRUE(x.HasMember(name));
|
||||
EXPECT_TRUE(y.HasMember(name));
|
||||
@ -1015,6 +1032,11 @@ TEST(Value, Object) {
|
||||
EXPECT_STREQ("Banana", y["B"].GetString());
|
||||
EXPECT_STREQ("CherryD", y[C0D].GetString());
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
EXPECT_STREQ("Apple", x["A"].GetString());
|
||||
EXPECT_STREQ("Apple", y[std::string("A")].GetString());
|
||||
#endif
|
||||
|
||||
// member iterator
|
||||
Value::MemberIterator itr = x.MemberBegin();
|
||||
EXPECT_TRUE(itr != x.MemberEnd());
|
||||
@ -1103,7 +1125,7 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(x.MemberBegin(), itr);
|
||||
EXPECT_EQ(9u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
size_t i = static_cast<size_t>((itr - x.MemberBegin())) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||
}
|
||||
@ -1114,7 +1136,7 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(x.MemberEnd(), itr);
|
||||
EXPECT_EQ(8u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
size_t i = static_cast<size_t>(itr - x.MemberBegin()) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||
}
|
||||
@ -1125,8 +1147,8 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
||||
EXPECT_EQ(7u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin());
|
||||
i += (i<4) ? 1 : 2;
|
||||
size_t i = static_cast<size_t>(itr - x.MemberBegin());
|
||||
i += (i < 4) ? 1 : 2;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||
}
|
||||
@ -1140,11 +1162,11 @@ TEST(Value, Object) {
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
|
||||
|
||||
itr = x.EraseMember(x.MemberBegin() + first, x.MemberBegin() + last);
|
||||
itr = x.EraseMember(x.MemberBegin() + static_cast<int>(first), x.MemberBegin() + static_cast<int>(last));
|
||||
if (last == n)
|
||||
EXPECT_EQ(x.MemberEnd(), itr);
|
||||
else
|
||||
EXPECT_EQ(x.MemberBegin() + first, itr);
|
||||
EXPECT_EQ(x.MemberBegin() + static_cast<int>(first), itr);
|
||||
|
||||
size_t removeCount = last - first;
|
||||
EXPECT_EQ(n - removeCount, x.MemberCount());
|
||||
@ -1166,6 +1188,24 @@ TEST(Value, Object) {
|
||||
EXPECT_TRUE(z.IsObject());
|
||||
}
|
||||
|
||||
TEST(Value, EraseMember_String) {
|
||||
Value::AllocatorType allocator;
|
||||
Value x(kObjectType);
|
||||
x.AddMember("A", "Apple", allocator);
|
||||
x.AddMember("B", "Banana", allocator);
|
||||
|
||||
EXPECT_TRUE(x.EraseMember("B"));
|
||||
EXPECT_FALSE(x.HasMember("B"));
|
||||
|
||||
EXPECT_FALSE(x.EraseMember("nonexist"));
|
||||
|
||||
GenericValue<UTF8<>, CrtAllocator> othername("A");
|
||||
EXPECT_TRUE(x.EraseMember(othername));
|
||||
EXPECT_FALSE(x.HasMember("A"));
|
||||
|
||||
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
||||
}
|
||||
|
||||
TEST(Value, BigNestedArray) {
|
||||
MemoryPoolAllocator<> allocator;
|
||||
Value x(kArrayType);
|
||||
@ -1174,7 +1214,7 @@ TEST(Value, BigNestedArray) {
|
||||
for (SizeType i = 0; i < n; i++) {
|
||||
Value y(kArrayType);
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
Value number((int)(i * n + j));
|
||||
Value number(static_cast<int>(i * n + j));
|
||||
y.PushBack(number, allocator);
|
||||
}
|
||||
x.PushBack(y, allocator);
|
||||
@ -1183,7 +1223,7 @@ TEST(Value, BigNestedArray) {
|
||||
for (SizeType i = 0; i < n; i++)
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
EXPECT_TRUE(x[i][j].IsInt());
|
||||
EXPECT_EQ((int)(i * n + j), x[i][j].GetInt());
|
||||
EXPECT_EQ(static_cast<int>(i * n + j), x[i][j].GetInt());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1197,16 +1237,16 @@ TEST(Value, BigNestedObject) {
|
||||
sprintf(name1, "%d", i);
|
||||
|
||||
// Value name(name1); // should not compile
|
||||
Value name(name1, (SizeType)strlen(name1), allocator);
|
||||
Value name(name1, static_cast<SizeType>(strlen(name1)), allocator);
|
||||
Value object(kObjectType);
|
||||
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
char name2[10];
|
||||
sprintf(name2, "%d", j);
|
||||
|
||||
Value name(name2, (SizeType)strlen(name2), allocator);
|
||||
Value number((int)(i * n + j));
|
||||
object.AddMember(name, number, allocator);
|
||||
Value name3(name2, static_cast<SizeType>(strlen(name2)), allocator);
|
||||
Value number(static_cast<int>(i * n + j));
|
||||
object.AddMember(name3, number, allocator);
|
||||
}
|
||||
|
||||
// x.AddMember(name1, object, allocator); // should not compile
|
||||
@ -1221,7 +1261,7 @@ TEST(Value, BigNestedObject) {
|
||||
char name2[10];
|
||||
sprintf(name2, "%d", j);
|
||||
x[name1];
|
||||
EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt());
|
||||
EXPECT_EQ(static_cast<int>(i * n + j), x[name1][name2].GetInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1253,7 +1293,7 @@ TEST(Document, CrtAllocator) {
|
||||
}
|
||||
|
||||
static void TestShortStringOptimization(const char* str) {
|
||||
const rapidjson::SizeType len = (rapidjson::SizeType)strlen(str);
|
||||
const rapidjson::SizeType len = static_cast<rapidjson::SizeType>(strlen(str));
|
||||
|
||||
rapidjson::Document doc;
|
||||
rapidjson::Value val;
|
||||
|
@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// 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:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// 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.
|
||||
// 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"
|
||||
|
||||
|
@ -66,7 +66,7 @@ gh_pages_prepare()
|
||||
[ ! -d "html" ] || \
|
||||
abort "Doxygen target directory already exists."
|
||||
git --version
|
||||
git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html
|
||||
git clone -b gh-pages "${GITHUB_CLONE}" html
|
||||
cd html
|
||||
# setup git config (with defaults)
|
||||
git config user.name "${GIT_NAME-travis}"
|
||||
@ -78,6 +78,7 @@ gh_pages_prepare()
|
||||
|
||||
gh_pages_commit() {
|
||||
cd "${TRAVIS_BUILD_DIR}/build/doc/html";
|
||||
echo "rapidjson.org" > CNAME
|
||||
git add --all;
|
||||
git diff-index --quiet HEAD || git commit -m "Automatic doxygen build";
|
||||
}
|
||||
|