Merge branch 'master' into schema
# Conflicts: # .gitignore # include/rapidjson/internal/stack.h
This commit is contained in:
commit
7f9921fc60
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,3 +1,11 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
/bin/*
|
||||||
|
!/bin/data
|
||||||
|
!/bin/encodings
|
||||||
|
!/bin/jsonchecker
|
||||||
|
!/bin/types
|
||||||
|
>>>>>>> master
|
||||||
/build
|
/build
|
||||||
/doc/html
|
/doc/html
|
||||||
/doc/doxygen_*.db
|
/doc/doxygen_*.db
|
||||||
@ -16,3 +24,4 @@ Testing
|
|||||||
install_manifest.txt
|
install_manifest.txt
|
||||||
Doxyfile
|
Doxyfile
|
||||||
DartConfiguration.tcl
|
DartConfiguration.tcl
|
||||||
|
*.nupkg
|
||||||
|
11
.travis.yml
11
.travis.yml
@ -6,10 +6,12 @@ compiler:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- CONF=debug ARCH=x86_64
|
- CONF=debug ARCH=x86_64 CXX11=ON
|
||||||
- CONF=release ARCH=x86_64
|
- CONF=release ARCH=x86_64 CXX11=ON
|
||||||
- CONF=debug ARCH=x86
|
- CONF=debug ARCH=x86 CXX11=ON
|
||||||
- CONF=release ARCH=x86
|
- CONF=release ARCH=x86 CXX11=ON
|
||||||
|
- CONF=debug ARCH=x86_64 CXX11=OFF
|
||||||
|
- CONF=debug ARCH=x86 CXX11=OFF
|
||||||
global:
|
global:
|
||||||
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
|
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
|
||||||
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
|
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
|
||||||
@ -34,6 +36,7 @@ before_script:
|
|||||||
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
|
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
|
||||||
(cd build && cmake
|
(cd build && cmake
|
||||||
-DRAPIDJSON_HAS_STDSTRING=ON
|
-DRAPIDJSON_HAS_STDSTRING=ON
|
||||||
|
-DRAPIDJSON_BUILD_CXX11=$CXX11
|
||||||
-DCMAKE_VERBOSE_MAKEFILE=ON
|
-DCMAKE_VERBOSE_MAKEFILE=ON
|
||||||
-DCMAKE_BUILD_TYPE=$CONF
|
-DCMAKE_BUILD_TYPE=$CONF
|
||||||
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
|
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
|
||||||
|
@ -20,6 +20,8 @@ option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON)
|
|||||||
option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
|
option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
|
||||||
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
|
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
|
||||||
|
|
||||||
|
option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
|
||||||
|
|
||||||
option(RAPIDJSON_HAS_STDSTRING "" OFF)
|
option(RAPIDJSON_HAS_STDSTRING "" OFF)
|
||||||
if(RAPIDJSON_HAS_STDSTRING)
|
if(RAPIDJSON_HAS_STDSTRING)
|
||||||
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
|
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
|
||||||
@ -27,8 +29,18 @@ endif()
|
|||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror")
|
||||||
|
if (RAPIDJSON_BUILD_CXX11)
|
||||||
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers")
|
||||||
|
if (RAPIDJSON_BUILD_CXX11)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif()
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||||
endif()
|
endif()
|
||||||
|
BIN
bin/types/booleans.json
Executable file
BIN
bin/types/booleans.json
Executable file
Binary file not shown.
BIN
bin/types/floats.json
Executable file
BIN
bin/types/floats.json
Executable file
Binary file not shown.
BIN
bin/types/guids.json
Executable file
BIN
bin/types/guids.json
Executable file
Binary file not shown.
BIN
bin/types/integers.json
Executable file
BIN
bin/types/integers.json
Executable file
Binary file not shown.
BIN
bin/types/mixed.json
Executable file
BIN
bin/types/mixed.json
Executable file
Binary file not shown.
BIN
bin/types/nulls.json
Executable file
BIN
bin/types/nulls.json
Executable file
Binary file not shown.
BIN
bin/types/paragraphs.json
Executable file
BIN
bin/types/paragraphs.json
Executable file
Binary file not shown.
1
bin/types/readme.txt
Normal file
1
bin/types/readme.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Test data obtained from https://github.com/xpol/lua-rapidjson/tree/master/performance
|
@ -764,18 +764,19 @@ WARN_LOGFILE =
|
|||||||
# spaces.
|
# spaces.
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = ./readme.zh-cn.md \
|
INPUT = readme.zh-cn.md \
|
||||||
./include/rapidjson/rapidjson.h \
|
include/rapidjson/rapidjson.h \
|
||||||
./include/ \
|
include/ \
|
||||||
./doc/features.zh-cn.md \
|
doc/features.zh-cn.md \
|
||||||
./doc/tutorial.zh-cn.md \
|
doc/tutorial.zh-cn.md \
|
||||||
./doc/stream.zh-cn.md \
|
doc/pointer.zh-cn.md \
|
||||||
./doc/encoding.zh-cn.md \
|
doc/stream.zh-cn.md \
|
||||||
./doc/dom.zh-cn.md \
|
doc/encoding.zh-cn.md \
|
||||||
./doc/sax.zh-cn.md \
|
doc/dom.zh-cn.md \
|
||||||
./doc/performance.zh-cn.md \
|
doc/sax.zh-cn.md \
|
||||||
./doc/internals.md \
|
doc/performance.zh-cn.md \
|
||||||
./doc/faq.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
|
# 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
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
|
@ -115,6 +115,7 @@ Parse flags | Meaning
|
|||||||
`kParseIterativeFlag` | Iterative(constant complexity in terms of function call stack size) parsing.
|
`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.
|
`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.
|
`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.
|
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.
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
|
|||||||
`kParseIterativeFlag` | 迭代式(调用堆栈大小为常数复杂度)解析。
|
`kParseIterativeFlag` | 迭代式(调用堆栈大小为常数复杂度)解析。
|
||||||
`kParseStopWhenDoneFlag` | 当从流解析了一个完整的JSON根节点之后,停止继续处理余下的流。当使用了此标志,解析器便不会产生`kParseErrorDocumentRootNotSingular`错误。可使用本标志去解析同一个流里的多个JSON。
|
`kParseStopWhenDoneFlag` | 当从流解析了一个完整的JSON根节点之后,停止继续处理余下的流。当使用了此标志,解析器便不会产生`kParseErrorDocumentRootNotSingular`错误。可使用本标志去解析同一个流里的多个JSON。
|
||||||
`kParseFullPrecisionFlag` | 使用完整的精确度去解析数字(较慢)。如不设置此标节,则会使用正常的精确度(较快)。正常精确度会有最多3个[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place)的误差。
|
`kParseFullPrecisionFlag` | 使用完整的精确度去解析数字(较慢)。如不设置此标节,则会使用正常的精确度(较快)。正常精确度会有最多3个[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place)的误差。
|
||||||
|
`kParseCommentsFlag` | 容许单行 `// ...` 及多行 `/* ... */` 注释(放宽的JSON语法)。
|
||||||
|
|
||||||
由于使用了非类型模板参数,而不是函数参数,C++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。
|
由于使用了非类型模板参数,而不是函数参数,C++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。
|
||||||
|
|
||||||
|
34
doc/faq.md
34
doc/faq.md
@ -106,59 +106,59 @@
|
|||||||
|
|
||||||
Call one of the `SetXXX()` methods - they call destructor which deallocates DOM data:
|
Call one of the `SetXXX()` methods - they call destructor which deallocates DOM data:
|
||||||
|
|
||||||
```
|
~~~~~~~~~~cpp
|
||||||
Document d;
|
Document d;
|
||||||
...
|
...
|
||||||
d.SetObject(); // clear and minimize
|
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):
|
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);
|
Value(kObjectType).Swap(d);
|
||||||
```
|
~~~~~~~~~~
|
||||||
or equivalent, but sightly longer to type:
|
or equivalent, but sightly longer to type:
|
||||||
```
|
~~~~~~~~~~cpp
|
||||||
d.Swap(Value(kObjectType).Move());
|
d.Swap(Value(kObjectType).Move());
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||
9. How to insert a document node into another document?
|
9. How to insert a document node into another document?
|
||||||
|
|
||||||
Let's take the following two DOM trees represented as JSON documents:
|
Let's take the following two DOM trees represented as JSON documents:
|
||||||
```
|
~~~~~~~~~~cpp
|
||||||
Document person;
|
Document person;
|
||||||
person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
|
person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
|
||||||
|
|
||||||
Document address;
|
Document address;
|
||||||
address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}");
|
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`:
|
Let's assume we want to merge them in such way that the whole `address` document becomes a node of the `person`:
|
||||||
```
|
~~~~~~~~~~js
|
||||||
{ "person": {
|
{ "person": {
|
||||||
"name": { "first": "Adam", "last": "Thomas" },
|
"name": { "first": "Adam", "last": "Thomas" },
|
||||||
"address": { "city": "Moscow", "street": "Quiet" }
|
"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.
|
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 nenber of the value:
|
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());
|
Documnet address(person.GetAllocator());
|
||||||
...
|
...
|
||||||
person["person"].AddMember("address", address["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:
|
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();
|
auto addressRoot = address.MemberBegin();
|
||||||
person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
|
person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||
Second way is to deep-clone the value from the address document:
|
Second way is to deep-clone the value from the address document:
|
||||||
```
|
~~~~~~~~~~cpp
|
||||||
Value addressValue = Value(address["address"], person.GetAllocator());
|
Value addressValue = Value(address["address"], person.GetAllocator());
|
||||||
person["person"].AddMember("address", addressValue, person.GetAllocator());
|
person["person"].AddMember("address", addressValue, person.GetAllocator());
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||
## Document/Value (DOM)
|
## Document/Value (DOM)
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
6. 怎样安装RapidJSON?
|
6. 怎样安装RapidJSON?
|
||||||
|
|
||||||
见[安装一节](readme.zh-cn.md)。
|
见[安装一节](../readme.zh-cn.md#安装)。
|
||||||
|
|
||||||
7. RapidJSON能否运行于我的平台?
|
7. RapidJSON能否运行于我的平台?
|
||||||
|
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
12. 有没有其他替代品?
|
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
|
## JSON
|
||||||
|
|
||||||
@ -98,10 +98,69 @@
|
|||||||
|
|
||||||
错误信息存储在`ParseResult`,它包含错误代号及偏移值(从JSON开始至错误处的字符数目)。可以把错误代号翻译为人类可读的错误讯息。
|
错误信息存储在`ParseResult`,它包含错误代号及偏移值(从JSON开始至错误处的字符数目)。可以把错误代号翻译为人类可读的错误讯息。
|
||||||
|
|
||||||
7. 为可不只使用`double`去表示JSON number?
|
7. 为何不只使用`double`去表示JSON number?
|
||||||
|
|
||||||
一些应用需要使用64位无号/有号整数。这些整数不能无损地转换成`double`。因此解析器会检测一个JSON number是否能转换至各种整数类型及`double`。
|
一些应用需要使用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)
|
## Document/Value (DOM)
|
||||||
|
|
||||||
1. 什么是转移语意?为什么?
|
1. 什么是转移语意?为什么?
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
* Support Unicode surrogate.
|
* Support Unicode surrogate.
|
||||||
* Support null character (`"\u0000"`)
|
* Support null character (`"\u0000"`)
|
||||||
* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
|
* 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
|
## Unicode
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
* 支持Unicod代理对(surrogate pair)。
|
* 支持Unicod代理对(surrogate pair)。
|
||||||
* 支持空字符(`"\u0000"`)。
|
* 支持空字符(`"\u0000"`)。
|
||||||
* 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。
|
* 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。
|
||||||
|
* 支持放宽的可选语法
|
||||||
|
* 单行(`// ...`)及多行(`/* ... */`) 注释。
|
||||||
|
|
||||||
## Unicode
|
## Unicode
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ When using `p.Get(root)` or `GetValueByPointer(root, p)`, `root` is a (const) `V
|
|||||||
|
|
||||||
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.
|
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 parameter is a `Document&`. But if you want to resolve a pointer to a subtree. You need to supply it as in the following example:
|
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
|
~~~cpp
|
||||||
class Person {
|
class Person {
|
||||||
@ -179,7 +179,7 @@ private:
|
|||||||
|
|
||||||
# Error Handling {#ErrorHandling}
|
# 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.
|
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.
|
Note that, all resolving functions assumes valid pointer. Resolving with an invalid pointer causes assertion failure.
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`.
|
|||||||
|
|
||||||
# User-Supplied Tokens {#UserSuppliedTokens}
|
# User-Supplied Tokens {#UserSuppliedTokens}
|
||||||
|
|
||||||
If a pointer will be resolved multiple times, it should be construct once, and then apply it to different DOMs or in different times. This reduce time and memory allocation for constructing `Pointer` multiple times.
|
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:
|
We can go one step further, to completely eliminate the parsing process and dynamic memory allocation, we can establish the token array directly:
|
||||||
|
|
||||||
|
234
doc/pointer.zh-cn.md
Normal file
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}
|
# Writer {#Writer}
|
||||||
|
|
||||||
`Reader`把JSON转换(解析)成为事件。`Writer`完全做相反的事情。它把事件转换成JSON。
|
`Reader`把JSON转换(解析)成为事件。`Writer`做完全相反的事情。它把事件转换成JSON。
|
||||||
|
|
||||||
`Writer`是非常容易使用的。若你的应用程序只需把一些数据转换成JSON,可能直接使用`Writer`,会比建立一个`Document`然后用`Writer`把它转换成JSON更加方便。
|
`Writer`是非常容易使用的。若你的应用程序只需把一些数据转换成JSON,可能直接使用`Writer`,会比建立一个`Document`然后用`Writer`把它转换成JSON更加方便。
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ public:
|
|||||||
|
|
||||||
## PrettyWriter {#PrettyWriter}
|
## PrettyWriter {#PrettyWriter}
|
||||||
|
|
||||||
`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但就适合人类阅读。
|
`Writer`所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但不适合人类阅读。
|
||||||
|
|
||||||
因此,RapidJSON提供了一个`PrettyWriter`,它在输出中加入缩进及换行。
|
因此,RapidJSON提供了一个`PrettyWriter`,它在输出中加入缩进及换行。
|
||||||
|
|
||||||
@ -386,13 +386,13 @@ Error: Terminate parsing due to Handler error.
|
|||||||
at offset 59 near '} }...'
|
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}
|
## 过滤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改为大写。
|
实际上,我们可以使用SAX风格API去加入(多个)中间层去过滤JSON的内容。例如`capitalize`例子可以把所有JSON string改为大写。
|
||||||
|
|
||||||
@ -472,5 +472,5 @@ int main(int, char*[]) {
|
|||||||
["HELLO\nWORLD"]
|
["HELLO\nWORLD"]
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对些一些处理情况,用DOM会比SAX更容易实现。
|
我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对于处理某些情况,用DOM会比SAX更容易实现。
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
本教程简介文件对象模型(Document Object Model, DOM)API。
|
本教程简介文件对象模型(Document Object Model, DOM)API。
|
||||||
|
|
||||||
如[用法一览](readme.zh-cn.md)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。
|
如[用法一览](../readme.zh-cn.md#用法一览)中所示,可以解析一个JSON至DOM,然后就可以轻松查询及修改DOM,并最终转换回JSON。
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ a[3] = 4
|
|||||||
|
|
||||||
你可以用整数字面量访问元素,如`a[0]`、`a[1]`、`a[2]`。
|
你可以用整数字面量访问元素,如`a[0]`、`a[1]`、`a[2]`。
|
||||||
|
|
||||||
Array与`std::vector`相似,除了使用索引,也可使用迭待器来访问所有元素。
|
Array与`std::vector`相似,除了使用索引,也可使用迭代器来访问所有元素。
|
||||||
~~~~~~~~~~cpp
|
~~~~~~~~~~cpp
|
||||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||||
printf("%d ", itr->GetInt());
|
printf("%d ", itr->GetInt());
|
||||||
@ -461,7 +461,7 @@ contact.AddMember(key, val, document.GetAllocator());
|
|||||||
|
|
||||||
* `bool RemoveMember(const Ch* name)`:使用键名来移除成员(线性时间复杂度)。
|
* `bool RemoveMember(const Ch* name)`:使用键名来移除成员(线性时间复杂度)。
|
||||||
* `bool RemoveMember(const Value& name)`:除了`name`是一个Value,和上一行相同。
|
* `bool RemoveMember(const Value& name)`:除了`name`是一个Value,和上一行相同。
|
||||||
* `MemberIterator RemoveMember(MemberIterator)`:使用迭待器移除成员(_常数_时间复杂度)。
|
* `MemberIterator RemoveMember(MemberIterator)`:使用迭代器移除成员(_常数_时间复杂度)。
|
||||||
* `MemberIterator EraseMember(MemberIterator)`:和上行相似但维持成员次序(线性时间复杂度)。
|
* `MemberIterator EraseMember(MemberIterator)`:和上行相似但维持成员次序(线性时间复杂度)。
|
||||||
* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`:移除一个范围内的成员,维持次序(线性时间复杂度)。
|
* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`:移除一个范围内的成员,维持次序(线性时间复杂度)。
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ include_directories("../include/")
|
|||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
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")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||||
endif()
|
endif()
|
||||||
|
@ -27,7 +27,7 @@ struct CapitalizeFilter {
|
|||||||
bool String(const char* str, SizeType length, bool) {
|
bool String(const char* str, SizeType length, bool) {
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
for (SizeType i = 0; i < length; i++)
|
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
|
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
|
||||||
}
|
}
|
||||||
bool StartObject() { return out_.StartObject(); }
|
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.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
|
CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
|
||||||
if (!reader.Parse(is, filter)) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ int main(int, char*[]) {
|
|||||||
|
|
||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
if (!reader.Parse(is, writer)) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ RAPIDJSON_DIAG_PUSH
|
|||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct MessageHandler
|
struct MessageHandler
|
||||||
: public BaseReaderHandler<UTF8<>, MessageHandler> {
|
: public BaseReaderHandler<UTF8<>, MessageHandler> {
|
||||||
MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
|
MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
|
||||||
@ -63,7 +68,11 @@ struct MessageHandler
|
|||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ParseMessages(const char* json, MessageMap& messages) {
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ParseMessages(const char* json, MessageMap& messages) {
|
||||||
Reader reader;
|
Reader reader;
|
||||||
MessageHandler handler;
|
MessageHandler handler;
|
||||||
StringStream ss(json);
|
StringStream ss(json);
|
||||||
|
@ -22,7 +22,7 @@ int main(int, char*[]) {
|
|||||||
|
|
||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ int main(int, char*[]) {
|
|||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
||||||
if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,17 +11,24 @@ using namespace rapidjson;
|
|||||||
class Person {
|
class Person {
|
||||||
public:
|
public:
|
||||||
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
|
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
|
||||||
|
Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {}
|
||||||
virtual ~Person();
|
virtual ~Person();
|
||||||
|
|
||||||
|
Person& operator=(const Person& rhs) {
|
||||||
|
name_ = rhs.name_;
|
||||||
|
age_ = rhs.age_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename Writer>
|
template <typename Writer>
|
||||||
void Serialize(Writer& writer) const {
|
void Serialize(Writer& writer) const {
|
||||||
// This base class just write out name-value pairs, without wrapping within an object.
|
// This base class just write out name-value pairs, without wrapping within an object.
|
||||||
writer.String("name");
|
writer.String("name");
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
writer.String(name_);
|
writer.String(name_);
|
||||||
#else
|
#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
|
#endif
|
||||||
writer.String("age");
|
writer.String("age");
|
||||||
writer.Uint(age_);
|
writer.Uint(age_);
|
||||||
@ -38,16 +45,17 @@ Person::~Person() {
|
|||||||
class Education {
|
class Education {
|
||||||
public:
|
public:
|
||||||
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
|
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
|
||||||
|
Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {}
|
||||||
|
|
||||||
template <typename Writer>
|
template <typename Writer>
|
||||||
void Serialize(Writer& writer) const {
|
void Serialize(Writer& writer) const {
|
||||||
writer.StartObject();
|
writer.StartObject();
|
||||||
|
|
||||||
writer.String("school");
|
writer.String("school");
|
||||||
#ifdef RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
writer.String(school_);
|
writer.String(school_);
|
||||||
#else
|
#else
|
||||||
writer.String(school_.c_str(), (SizeType)school_.length());
|
writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
writer.String("GPA");
|
writer.String("GPA");
|
||||||
@ -102,8 +110,16 @@ Dependent::~Dependent() {
|
|||||||
class Employee : public Person {
|
class Employee : public Person {
|
||||||
public:
|
public:
|
||||||
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
|
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
|
||||||
|
Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {}
|
||||||
virtual ~Employee();
|
virtual ~Employee();
|
||||||
|
|
||||||
|
Employee& operator=(const Employee& rhs) {
|
||||||
|
static_cast<Person&>(*this) = rhs;
|
||||||
|
dependents_ = rhs.dependents_;
|
||||||
|
married_ = rhs.married_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void AddDependent(const Dependent& dependent) {
|
void AddDependent(const Dependent& dependent) {
|
||||||
dependents_.push_back(dependent);
|
dependents_.push_back(dependent);
|
||||||
}
|
}
|
||||||
|
@ -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.
|
// 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;
|
Value author;
|
||||||
{
|
{
|
||||||
char buffer[10];
|
char buffer2[10];
|
||||||
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
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:
|
// Shorter but slower version:
|
||||||
// document["hello"].SetString(buffer, document.GetAllocator());
|
// document["hello"].SetString(buffer, document.GetAllocator());
|
||||||
|
|
||||||
// Constructor version:
|
// Constructor version:
|
||||||
// Value author(buffer, len, document.GetAllocator());
|
// Value author(buffer, len, document.GetAllocator());
|
||||||
// Value author(buffer, 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.
|
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||||
document.AddMember("author", author, document.GetAllocator());
|
document.AddMember("author", author, document.GetAllocator());
|
||||||
|
@ -199,7 +199,7 @@ public:
|
|||||||
return originalPtr;
|
return originalPtr;
|
||||||
|
|
||||||
// Simply expand it if it is the last allocation and there is sufficient space
|
// Simply expand it if it is the last allocation and there is sufficient space
|
||||||
if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + 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);
|
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||||
increment = RAPIDJSON_ALIGN(increment);
|
increment = RAPIDJSON_ALIGN(increment);
|
||||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||||
|
@ -25,36 +25,20 @@
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
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)
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#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
|
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
#include <iterator> // std::iterator, std::random_access_iterator_tag
|
||||||
#endif
|
#endif
|
||||||
@ -158,6 +142,7 @@ public:
|
|||||||
Otherwise, the copy constructor is implicitly defined.
|
Otherwise, the copy constructor is implicitly defined.
|
||||||
*/
|
*/
|
||||||
GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
|
GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
|
||||||
|
Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
|
||||||
|
|
||||||
//! @name stepping
|
//! @name stepping
|
||||||
//@{
|
//@{
|
||||||
@ -260,6 +245,7 @@ struct GenericStringRef {
|
|||||||
typedef CharType Ch; //!< character type of the string
|
typedef CharType Ch; //!< character type of the string
|
||||||
|
|
||||||
//! Create string reference from \c const character array
|
//! Create string reference from \c const character array
|
||||||
|
#ifndef __clang__ // -Wdocumentation
|
||||||
/*!
|
/*!
|
||||||
This constructor implicitly creates a constant string reference from
|
This constructor implicitly creates a constant string reference from
|
||||||
a \c const character array. It has better performance than
|
a \c const character array. It has better performance than
|
||||||
@ -282,11 +268,13 @@ struct GenericStringRef {
|
|||||||
In such cases, the referenced string should be \b copied to the
|
In such cases, the referenced string should be \b copied to the
|
||||||
GenericValue instead.
|
GenericValue instead.
|
||||||
*/
|
*/
|
||||||
|
#endif
|
||||||
template<SizeType N>
|
template<SizeType N>
|
||||||
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
|
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
|
||||||
: s(str), length(N-1) {}
|
: s(str), length(N-1) {}
|
||||||
|
|
||||||
//! Explicitly create string reference from \c const character pointer
|
//! Explicitly create string reference from \c const character pointer
|
||||||
|
#ifndef __clang__ // -Wdocumentation
|
||||||
/*!
|
/*!
|
||||||
This constructor can be used to \b explicitly create a reference to
|
This constructor can be used to \b explicitly create a reference to
|
||||||
a constant string pointer.
|
a constant string pointer.
|
||||||
@ -305,16 +293,19 @@ struct GenericStringRef {
|
|||||||
In such cases, the referenced string should be \b copied to the
|
In such cases, the referenced string should be \b copied to the
|
||||||
GenericValue instead.
|
GenericValue instead.
|
||||||
*/
|
*/
|
||||||
|
#endif
|
||||||
explicit GenericStringRef(const CharType* str)
|
explicit GenericStringRef(const CharType* str)
|
||||||
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
|
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
|
||||||
|
|
||||||
//! Create constant string reference from pointer and length
|
//! 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 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
|
\param len length of the string, excluding the trailing NULL terminator
|
||||||
|
|
||||||
\post \ref s == str && \ref length == len
|
\post \ref s == str && \ref length == len
|
||||||
\note Constant complexity.
|
\note Constant complexity.
|
||||||
*/
|
*/
|
||||||
|
#endif
|
||||||
GenericStringRef(const CharType* str, SizeType len)
|
GenericStringRef(const CharType* str, SizeType len)
|
||||||
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
|
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
|
||||||
|
|
||||||
@ -325,8 +316,6 @@ struct GenericStringRef {
|
|||||||
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
|
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Disallow copy-assignment
|
|
||||||
GenericStringRef operator=(const GenericStringRef&);
|
|
||||||
//! Disallow construction from non-const array
|
//! Disallow construction from non-const array
|
||||||
template<SizeType N>
|
template<SizeType N>
|
||||||
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
||||||
@ -654,7 +643,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename SourceAllocator>
|
template <typename SourceAllocator>
|
||||||
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
|
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();
|
this->~GenericValue();
|
||||||
new (this) GenericValue(rhs, allocator);
|
new (this) GenericValue(rhs, allocator);
|
||||||
return *this;
|
return *this;
|
||||||
@ -736,7 +725,7 @@ public:
|
|||||||
else
|
else
|
||||||
return data_.n.u64 == rhs.data_.n.u64;
|
return data_.n.u64 == rhs.data_.n.u64;
|
||||||
|
|
||||||
default: // kTrueType, kFalseType, kNullType
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -864,8 +853,14 @@ public:
|
|||||||
return member->value;
|
return member->value;
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_ASSERT(false); // see above note
|
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>
|
template <typename SourceAllocator>
|
||||||
@ -1235,8 +1230,8 @@ public:
|
|||||||
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
||||||
for (MemberIterator itr = pos; itr != last; ++itr)
|
for (MemberIterator itr = pos; itr != last; ++itr)
|
||||||
itr->~Member();
|
itr->~Member();
|
||||||
std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));
|
std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
|
||||||
data_.o.size -= (last - first);
|
data_.o.size -= static_cast<SizeType>(last - first);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,7 +1323,7 @@ public:
|
|||||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
if (newCapacity > data_.a.capacity) {
|
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;
|
data_.a.capacity = newCapacity;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -1435,8 +1430,8 @@ public:
|
|||||||
ValueIterator pos = Begin() + (first - Begin());
|
ValueIterator pos = Begin() + (first - Begin());
|
||||||
for (ValueIterator itr = pos; itr != last; ++itr)
|
for (ValueIterator itr = pos; itr != last; ++itr)
|
||||||
itr->~GenericValue();
|
itr->~GenericValue();
|
||||||
std::memmove(pos, last, (End() - last) * sizeof(GenericValue));
|
std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
|
||||||
data_.a.size -= (last - first);
|
data_.a.size -= static_cast<SizeType>(last - first);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1455,8 +1450,8 @@ public:
|
|||||||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
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_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
|
||||||
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> 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)
|
if ((flags_ & kInt64Flag) != 0) return static_cast<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)
|
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; }
|
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
|
||||||
@ -1628,9 +1623,9 @@ private:
|
|||||||
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
|
||||||
Ch str[MaxChars];
|
Ch str[MaxChars];
|
||||||
|
|
||||||
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
inline static bool Usable(SizeType len) { return (MaxSize >= len); }
|
||||||
inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); }
|
inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
|
||||||
inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); }
|
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
|
}; // 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.
|
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
||||||
@ -1683,7 +1678,7 @@ private:
|
|||||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kArrayFlag;
|
flags_ = kArrayFlag;
|
||||||
if (count) {
|
if (count) {
|
||||||
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
|
data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
|
||||||
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1695,7 +1690,7 @@ private:
|
|||||||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
||||||
flags_ = kObjectFlag;
|
flags_ = kObjectFlag;
|
||||||
if (count) {
|
if (count) {
|
||||||
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
|
data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||||
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
std::memcpy(data_.o.members, members, count * sizeof(Member));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1720,7 +1715,7 @@ private:
|
|||||||
} else {
|
} else {
|
||||||
flags_ = kCopyStringFlag;
|
flags_ = kCopyStringFlag;
|
||||||
data_.s.length = s.length;
|
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;
|
data_.s.str = str;
|
||||||
}
|
}
|
||||||
std::memcpy(str, s, s.length * sizeof(Ch));
|
std::memcpy(str, s, s.length * sizeof(Ch));
|
||||||
@ -1847,7 +1842,7 @@ public:
|
|||||||
|
|
||||||
//! Exchange the contents of this document with those of another.
|
//! Exchange the contents of this document with those of another.
|
||||||
/*!
|
/*!
|
||||||
\param other Another document.
|
\param rhs Another document.
|
||||||
\note Constant complexity.
|
\note Constant complexity.
|
||||||
\see GenericValue::Swap
|
\see GenericValue::Swap
|
||||||
*/
|
*/
|
||||||
@ -1886,13 +1881,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
|
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
|
||||||
GenericDocument& ParseStream(InputStream& is) {
|
GenericDocument& ParseStream(InputStream& is) {
|
||||||
ValueType::SetNull(); // Remove existing root if exist
|
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
|
||||||
GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());
|
stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
|
||||||
ClearStackOnExit scope(*this);
|
ClearStackOnExit scope(*this);
|
||||||
parseResult_ = reader.template Parse<parseFlags>(is, *this);
|
parseResult_ = reader.template Parse<parseFlags>(is, *this);
|
||||||
if (parseResult_) {
|
if (parseResult_) {
|
||||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1951,7 +1946,7 @@ public:
|
|||||||
\param str Read-only zero-terminated string to be parsed.
|
\param str Read-only zero-terminated string to be parsed.
|
||||||
*/
|
*/
|
||||||
template <unsigned parseFlags, typename SourceEncoding>
|
template <unsigned parseFlags, typename SourceEncoding>
|
||||||
GenericDocument& Parse(const Ch* str) {
|
GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
|
||||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||||
GenericStringStream<SourceEncoding> s(str);
|
GenericStringStream<SourceEncoding> s(str);
|
||||||
return ParseStream<parseFlags, SourceEncoding>(s);
|
return ParseStream<parseFlags, SourceEncoding>(s);
|
||||||
@ -1986,10 +1981,26 @@ public:
|
|||||||
//! Get the position of last parsing error in input, 0 otherwise.
|
//! Get the position of last parsing error in input, 0 otherwise.
|
||||||
size_t GetErrorOffset() const { return parseResult_.Offset(); }
|
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.
|
//! Get the allocator of this document.
|
||||||
Allocator& GetAllocator() { return *allocator_; }
|
Allocator& GetAllocator() {
|
||||||
|
RAPIDJSON_ASSERT(allocator_);
|
||||||
|
return *allocator_;
|
||||||
|
}
|
||||||
|
|
||||||
//! Get the capacity of stack in bytes.
|
//! Get the capacity of stack in bytes.
|
||||||
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
||||||
@ -2032,7 +2043,7 @@ private:
|
|||||||
|
|
||||||
bool EndObject(SizeType memberCount) {
|
bool EndObject(SizeType memberCount) {
|
||||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2095,15 +2106,24 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
|
|||||||
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
|
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: // kNumberType, kTrueType, kFalseType, kNullType
|
default:
|
||||||
flags_ = rhs.flags_;
|
flags_ = rhs.flags_;
|
||||||
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
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
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH
|
|||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Input byte stream wrapper with a statically bound encoding.
|
//! Input byte stream wrapper with a statically bound encoding.
|
||||||
@ -60,7 +65,7 @@ private:
|
|||||||
//! Output byte stream wrapper with statically bound encoding.
|
//! Output byte stream wrapper with statically bound encoding.
|
||||||
/*!
|
/*!
|
||||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
\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>
|
template <typename Encoding, typename OutputByteStream>
|
||||||
class EncodedOutputStream {
|
class EncodedOutputStream {
|
||||||
@ -77,8 +82,8 @@ public:
|
|||||||
void Flush() { os_.Flush(); }
|
void Flush() { os_.Flush(); }
|
||||||
|
|
||||||
// Not implemented
|
// Not implemented
|
||||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
@ -142,7 +147,7 @@ private:
|
|||||||
// FF FE UTF-16LE
|
// FF FE UTF-16LE
|
||||||
// EF BB BF UTF-8
|
// 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)
|
if (!c)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -193,7 +198,7 @@ private:
|
|||||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
/*!
|
/*!
|
||||||
\tparam CharType Type of character for writing.
|
\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>
|
template <typename CharType, typename OutputByteStream>
|
||||||
class AutoUTFOutputStream {
|
class AutoUTFOutputStream {
|
||||||
@ -227,8 +232,8 @@ public:
|
|||||||
void Flush() { os_->Flush(); }
|
void Flush() { os_->Flush(); }
|
||||||
|
|
||||||
// Not implemented
|
// Not implemented
|
||||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
@ -254,6 +259,10 @@ private:
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
@ -120,19 +120,41 @@ struct UTF8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||||
#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)
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
Ch c = is.Take();
|
typename InputStream::Ch c = is.Take();
|
||||||
if (!(c & 0x80)) {
|
if (!(c & 0x80)) {
|
||||||
*codepoint = (unsigned char)c;
|
*codepoint = static_cast<unsigned char>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char type = GetRange((unsigned char)c);
|
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||||
*codepoint = (0xFF >> type) & (unsigned char)c;
|
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
|
||||||
bool result = true;
|
bool result = true;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 2: TAIL(); return result;
|
case 2: TAIL(); return result;
|
||||||
@ -152,7 +174,7 @@ struct UTF8 {
|
|||||||
template <typename InputStream, typename OutputStream>
|
template <typename InputStream, typename OutputStream>
|
||||||
static bool Validate(InputStream& is, OutputStream& os) {
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
#define COPY() os.Put(c = is.Take())
|
#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)
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
Ch c;
|
Ch c;
|
||||||
COPY();
|
COPY();
|
||||||
@ -160,7 +182,7 @@ struct UTF8 {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
switch (GetRange((unsigned char)c)) {
|
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||||
case 2: TAIL(); return result;
|
case 2: TAIL(); return result;
|
||||||
case 3: TAIL(); TAIL(); return result;
|
case 3: TAIL(); TAIL(); return result;
|
||||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
@ -196,12 +218,12 @@ struct UTF8 {
|
|||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
Ch c = Take(is);
|
typename InputByteStream::Ch c = Take(is);
|
||||||
if ((unsigned char)c != 0xEFu) return c;
|
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||||
c = is.Take();
|
c = is.Take();
|
||||||
if ((unsigned char)c != 0xBBu) return c;
|
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||||
c = is.Take();
|
c = is.Take();
|
||||||
if ((unsigned char)c != 0xBFu) return c;
|
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||||
c = is.Take();
|
c = is.Take();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -209,13 +231,15 @@ struct UTF8 {
|
|||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static Ch Take(InputByteStream& is) {
|
static Ch Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
return is.Take();
|
return static_cast<Ch>(is.Take());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
static void PutBOM(OutputByteStream& os) {
|
static void PutBOM(OutputByteStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
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>
|
template <typename OutputByteStream>
|
||||||
@ -259,18 +283,34 @@ struct UTF16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
PutUnsafe(os, (v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
Ch c = is.Take();
|
typename InputStream::Ch c = is.Take();
|
||||||
if (c < 0xD800 || c > 0xDFFF) {
|
if (c < 0xD800 || c > 0xDFFF) {
|
||||||
*codepoint = c;
|
*codepoint = static_cast<unsigned>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (c <= 0xDBFF) {
|
else if (c <= 0xDBFF) {
|
||||||
*codepoint = (c & 0x3FF) << 10;
|
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||||
c = is.Take();
|
c = is.Take();
|
||||||
*codepoint |= (c & 0x3FF);
|
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||||
*codepoint += 0x10000;
|
*codepoint += 0x10000;
|
||||||
return c >= 0xDC00 && c <= 0xDFFF;
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
}
|
}
|
||||||
@ -281,8 +321,8 @@ struct UTF16 {
|
|||||||
static bool Validate(InputStream& is, OutputStream& os) {
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
Ch c;
|
typename InputStream::Ch c;
|
||||||
os.Put(c = is.Take());
|
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||||
if (c < 0xD800 || c > 0xDFFF)
|
if (c < 0xD800 || c > 0xDFFF)
|
||||||
return true;
|
return true;
|
||||||
else if (c <= 0xDBFF) {
|
else if (c <= 0xDBFF) {
|
||||||
@ -300,28 +340,29 @@ struct UTF16LE : UTF16<CharType> {
|
|||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = Take(is);
|
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>
|
template <typename InputByteStream>
|
||||||
static CharType Take(InputByteStream& is) {
|
static CharType Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = (unsigned char)is.Take();
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
c |= (unsigned char)is.Take() << 8;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
return c;
|
return static_cast<CharType>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
static void PutBOM(OutputByteStream& os) {
|
static void PutBOM(OutputByteStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
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>
|
template <typename OutputByteStream>
|
||||||
static void Put(OutputByteStream& os, CharType c) {
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
os.Put(c & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
os.Put((c >> 8) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -332,28 +373,29 @@ struct UTF16BE : UTF16<CharType> {
|
|||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = Take(is);
|
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>
|
template <typename InputByteStream>
|
||||||
static CharType Take(InputByteStream& is) {
|
static CharType Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = (unsigned char)is.Take() << 8;
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
c |= (unsigned char)is.Take();
|
c |= static_cast<uint8_t>(is.Take());
|
||||||
return c;
|
return static_cast<CharType>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
static void PutBOM(OutputByteStream& os) {
|
static void PutBOM(OutputByteStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
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>
|
template <typename OutputByteStream>
|
||||||
static void Put(OutputByteStream& os, CharType c) {
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
os.Put((c >> 8) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
os.Put(c & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -382,6 +424,13 @@ struct UTF32 {
|
|||||||
os.Put(codepoint);
|
os.Put(codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
@ -406,32 +455,35 @@ struct UTF32LE : UTF32<CharType> {
|
|||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = Take(is);
|
CharType c = Take(is);
|
||||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static CharType Take(InputByteStream& is) {
|
static CharType Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = (unsigned char)is.Take();
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
c |= (unsigned char)is.Take() << 8;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
c |= (unsigned char)is.Take() << 16;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
c |= (unsigned char)is.Take() << 24;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
return c;
|
return static_cast<CharType>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
static void PutBOM(OutputByteStream& os) {
|
static void PutBOM(OutputByteStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
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>
|
template <typename OutputByteStream>
|
||||||
static void Put(OutputByteStream& os, CharType c) {
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
os.Put(c & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
os.Put((c >> 8) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
os.Put((c >> 16) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
os.Put((c >> 24) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -442,32 +494,35 @@ struct UTF32BE : UTF32<CharType> {
|
|||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = Take(is);
|
CharType c = Take(is);
|
||||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static CharType Take(InputByteStream& is) {
|
static CharType Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
CharType c = (unsigned char)is.Take() << 24;
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
c |= (unsigned char)is.Take() << 16;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
c |= (unsigned char)is.Take() << 8;
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
c |= (unsigned char)is.Take();
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||||
return c;
|
return static_cast<CharType>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
static void PutBOM(OutputByteStream& os) {
|
static void PutBOM(OutputByteStream& os) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
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>
|
template <typename OutputByteStream>
|
||||||
static void Put(OutputByteStream& os, CharType c) {
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
os.Put((c >> 24) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
os.Put((c >> 16) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
os.Put((c >> 8) & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
os.Put(c & 0xFFu);
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -491,31 +546,37 @@ struct ASCII {
|
|||||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
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;
|
*codepoint = c;
|
||||||
return c <= 0X7F;
|
return c <= 0X7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputStream, typename OutputStream>
|
template <typename InputStream, typename OutputStream>
|
||||||
static bool Validate(InputStream& is, OutputStream& os) {
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
unsigned char c = is.Take();
|
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||||
os.Put(c);
|
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||||
return c <= 0x7F;
|
return c <= 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static CharType TakeBOM(InputByteStream& is) {
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
Ch c = Take(is);
|
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||||
return c;
|
return static_cast<Ch>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputByteStream>
|
template <typename InputByteStream>
|
||||||
static Ch Take(InputByteStream& is) {
|
static Ch Take(InputByteStream& is) {
|
||||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
return is.Take();
|
return static_cast<Ch>(is.Take());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputByteStream>
|
template <typename OutputByteStream>
|
||||||
@ -561,6 +622,13 @@ struct AutoUTF {
|
|||||||
(*f[os.GetType()])(os, codepoint);
|
(*f[os.GetType()])(os, codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputStream>
|
template <typename InputStream>
|
||||||
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||||
@ -594,6 +662,15 @@ struct Transcoder {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//! Validate one Unicode codepoint from an encoded stream.
|
//! Validate one Unicode codepoint from an encoded stream.
|
||||||
template<typename InputStream, typename OutputStream>
|
template<typename InputStream, typename OutputStream>
|
||||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
@ -601,6 +678,10 @@ struct Transcoder {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Forward declaration.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||||
|
|
||||||
//! Specialization of Transcoder with same source and target encoding.
|
//! Specialization of Transcoder with same source and target encoding.
|
||||||
template<typename Encoding>
|
template<typename Encoding>
|
||||||
struct Transcoder<Encoding, Encoding> {
|
struct Transcoder<Encoding, Encoding> {
|
||||||
@ -610,6 +691,12 @@ struct Transcoder<Encoding, Encoding> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename InputStream, typename OutputStream>
|
template<typename InputStream, typename OutputStream>
|
||||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||||
@ -618,7 +705,7 @@ struct Transcoder<Encoding, Encoding> {
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(_MSV_VER)
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -12,11 +12,17 @@
|
|||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
#ifndef RAPIDJSON_ERROR_EN_H__
|
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||||
#define RAPIDJSON_ERROR_EN_H__
|
#define RAPIDJSON_ERROR_EN_H_
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Maps error code of parsing into error message.
|
//! 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 kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||||
|
|
||||||
default:
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#endif // RAPIDJSON_ERROR_EN_H__
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_EN_H_
|
||||||
|
@ -12,11 +12,16 @@
|
|||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||||
#define RAPIDJSON_ERROR_ERROR_H__
|
#define RAPIDJSON_ERROR_ERROR_H_
|
||||||
|
|
||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*! \file error.h */
|
/*! \file error.h */
|
||||||
|
|
||||||
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||||
@ -99,7 +104,7 @@ enum ParseErrorCode {
|
|||||||
\see GenericReader::Parse, GenericDocument::Parse
|
\see GenericReader::Parse, GenericDocument::Parse
|
||||||
*/
|
*/
|
||||||
struct ParseResult {
|
struct ParseResult {
|
||||||
|
public:
|
||||||
//! Default constructor, no error.
|
//! Default constructor, no error.
|
||||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||||
//! Constructor to set an error.
|
//! Constructor to set an error.
|
||||||
@ -143,4 +148,8 @@ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
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 "rapidjson.h"
|
||||||
#include <cstdio>
|
#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
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! File byte stream for input using fread().
|
//! File byte stream for input using fread().
|
||||||
@ -85,4 +92,8 @@ private:
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_FILESTREAM_H_
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
#include "rapidjson.h"
|
#include "rapidjson.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Wrapper of C file stream for input using fread().
|
//! Wrapper of C file stream for input using fread().
|
||||||
@ -57,7 +62,11 @@ public:
|
|||||||
|
|
||||||
void Flush() {
|
void Flush() {
|
||||||
if (current_ != buffer_) {
|
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_;
|
current_ = buffer_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,4 +97,8 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_FILESTREAM_H_
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
|
@ -240,7 +240,7 @@ private:
|
|||||||
uint64_t r = 0;
|
uint64_t r = 0;
|
||||||
for (const char* p = begin; p != end; ++p) {
|
for (const char* p = begin; p != end; ++p) {
|
||||||
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||||
r = r * 10u + (unsigned)(*p - '0');
|
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,11 @@ RAPIDJSON_DIAG_PUSH
|
|||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct DiyFp {
|
struct DiyFp {
|
||||||
DiyFp() {}
|
DiyFp() {}
|
||||||
|
|
||||||
@ -242,6 +247,11 @@ inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
|||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public:
|
|||||||
else if (order <= -1074)
|
else if (order <= -1074)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return (unsigned)order + 1074;
|
return static_cast<unsigned>(order) + 1074;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
#include "swap.h"
|
#include "swap.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
@ -108,11 +113,21 @@ public:
|
|||||||
// Optimization note: try to minimize the size of this function for force inline.
|
// Optimization note: try to minimize the size of this function for force inline.
|
||||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||||
// Expand the stack if needed
|
// Expand the stack if needed
|
||||||
if (stackTop_ + sizeof(T) * count >= stackEnd_)
|
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||||
Expand<T>(count);
|
Expand<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||||
|
Reserve<T>(count);
|
||||||
|
return PushUnsafe<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||||
|
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
stackTop_ += sizeof(T) * count;
|
stackTop_ += sizeof(T) * count;
|
||||||
return ret;
|
return ret;
|
||||||
@ -132,6 +147,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
<<<<<<< HEAD
|
||||||
const T* Top() const {
|
const T* Top() const {
|
||||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
@ -150,6 +166,18 @@ public:
|
|||||||
const T* Bottom() const { return (T*)stack_; }
|
const T* Bottom() const { return (T*)stack_; }
|
||||||
|
|
||||||
Allocator& GetAllocator() { return *allocator_; }
|
Allocator& GetAllocator() { return *allocator_; }
|
||||||
|
=======
|
||||||
|
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||||
|
|
||||||
|
bool HasAllocator() const {
|
||||||
|
return allocator_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator& GetAllocator() {
|
||||||
|
RAPIDJSON_ASSERT(allocator_);
|
||||||
|
return *allocator_;
|
||||||
|
}
|
||||||
|
>>>>>>> master
|
||||||
bool Empty() const { return stackTop_ == stack_; }
|
bool Empty() const { return stackTop_ == stack_; }
|
||||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||||
@ -176,7 +204,7 @@ private:
|
|||||||
|
|
||||||
void Resize(size_t newCapacity) {
|
void Resize(size_t newCapacity) {
|
||||||
const size_t size = GetSize(); // Backup the current size
|
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;
|
stackTop_ = stack_ + size;
|
||||||
stackEnd_ = stack_ + newCapacity;
|
stackEnd_ = stack_ + newCapacity;
|
||||||
}
|
}
|
||||||
@ -201,4 +229,8 @@ private:
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_STACK_H_
|
#endif // RAPIDJSON_STACK_H_
|
||||||
|
@ -149,7 +149,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
|||||||
v = v.Normalize();
|
v = v.Normalize();
|
||||||
error <<= -v.e;
|
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;
|
int actualExp;
|
||||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
@ -206,7 +206,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
|
|||||||
|
|
||||||
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
const BigInteger dInt(decimals, length);
|
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);
|
Double a(approx);
|
||||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
if (cmp < 0)
|
if (cmp < 0)
|
||||||
@ -246,8 +246,8 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
|
|||||||
|
|
||||||
// Trim right-most digits
|
// Trim right-most digits
|
||||||
const int kMaxDecimalDigit = 780;
|
const int kMaxDecimalDigit = 780;
|
||||||
if ((int)length > kMaxDecimalDigit) {
|
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
||||||
int delta = (int(length) - kMaxDecimalDigit);
|
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
||||||
exp += delta;
|
exp += delta;
|
||||||
decimalPosition -= static_cast<unsigned>(delta);
|
decimalPosition -= static_cast<unsigned>(delta);
|
||||||
length = kMaxDecimalDigit;
|
length = kMaxDecimalDigit;
|
||||||
|
@ -17,10 +17,15 @@
|
|||||||
|
|
||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
//! Custom swap() to avoid dependency on C++ <algorith> header
|
//! 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.
|
/*! \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().
|
\note This has the same semantics as std::swap().
|
||||||
*/
|
*/
|
||||||
@ -34,4 +39,8 @@ inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
#include "rapidjson.h"
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Represents an in-memory input byte stream.
|
//! Represents an in-memory input byte stream.
|
||||||
@ -58,4 +64,8 @@ struct MemoryStream {
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
@ -89,14 +89,14 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
// 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++" {}'
|
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||||
// or compiler give many errors like this:
|
// or compiler would give many errors like this:
|
||||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
# include <wchar.h>
|
# include <wchar.h>
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "internal/itoa.h"
|
#include "internal/itoa.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
|
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
|
||||||
@ -71,7 +76,7 @@ template <typename ValueType, typename Allocator = CrtAllocator>
|
|||||||
class GenericPointer {
|
class GenericPointer {
|
||||||
public:
|
public:
|
||||||
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
|
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
|
||||||
typedef typename EncodingType::Ch Ch; //!< Character type from Value
|
typedef typename ValueType::Ch Ch; //!< Character type from Value
|
||||||
|
|
||||||
//! A token is the basic units of internal representation.
|
//! A token is the basic units of internal representation.
|
||||||
/*!
|
/*!
|
||||||
@ -253,11 +258,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
|
GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
|
||||||
char buffer[21];
|
char buffer[21];
|
||||||
SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer;
|
char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
|
||||||
|
SizeType length = static_cast<SizeType>(end - buffer);
|
||||||
buffer[length] = '\0';
|
buffer[length] = '\0';
|
||||||
|
|
||||||
if (sizeof(Ch) == 1) {
|
if (sizeof(Ch) == 1) {
|
||||||
Token token = { (Ch*)buffer, length, index };
|
Token token = { reinterpret_cast<Ch*>(buffer), length, index };
|
||||||
return Append(token, allocator);
|
return Append(token, allocator);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -271,7 +277,7 @@ public:
|
|||||||
|
|
||||||
//! Append a token by value, and return a new Pointer
|
//! Append a token by value, and return a new Pointer
|
||||||
/*!
|
/*!
|
||||||
\param value Value (either Uint or String) to be appended.
|
\param token token to be appended.
|
||||||
\param allocator Allocator for the newly return Pointer.
|
\param allocator Allocator for the newly return Pointer.
|
||||||
\return A new Pointer with appended token.
|
\return A new Pointer with appended token.
|
||||||
*/
|
*/
|
||||||
@ -393,7 +399,7 @@ public:
|
|||||||
bool exist = true;
|
bool exist = true;
|
||||||
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
||||||
if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
|
if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
|
||||||
v->PushBack(Value().Move(), allocator);
|
v->PushBack(ValueType().Move(), allocator);
|
||||||
v = &((*v)[v->Size() - 1]);
|
v = &((*v)[v->Size() - 1]);
|
||||||
exist = false;
|
exist = false;
|
||||||
}
|
}
|
||||||
@ -411,7 +417,7 @@ public:
|
|||||||
if (t->index >= v->Size()) {
|
if (t->index >= v->Size()) {
|
||||||
v->Reserve(t->index + 1, allocator);
|
v->Reserve(t->index + 1, allocator);
|
||||||
while (t->index >= v->Size())
|
while (t->index >= v->Size())
|
||||||
v->PushBack(Value().Move(), allocator);
|
v->PushBack(ValueType().Move(), allocator);
|
||||||
exist = false;
|
exist = false;
|
||||||
}
|
}
|
||||||
v = &((*v)[t->index]);
|
v = &((*v)[t->index]);
|
||||||
@ -419,7 +425,7 @@ public:
|
|||||||
else {
|
else {
|
||||||
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
|
||||||
if (m == v->MemberEnd()) {
|
if (m == v->MemberEnd()) {
|
||||||
v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator);
|
v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
|
||||||
v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
|
v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
|
||||||
exist = false;
|
exist = false;
|
||||||
}
|
}
|
||||||
@ -438,7 +444,6 @@ public:
|
|||||||
//! Creates a value in a document.
|
//! Creates a value in a document.
|
||||||
/*!
|
/*!
|
||||||
\param document A document to be resolved.
|
\param document A document to be resolved.
|
||||||
\param allocator Allocator for creating the values if the specified value or its parents are not exist.
|
|
||||||
\param alreadyExist If non-null, it stores whether the resolved value is already exist.
|
\param alreadyExist If non-null, it stores whether the resolved value is already exist.
|
||||||
\return The resolved newly created, or already exists value.
|
\return The resolved newly created, or already exists value.
|
||||||
*/
|
*/
|
||||||
@ -528,7 +533,7 @@ public:
|
|||||||
|
|
||||||
//! Query a value in a subtree with default primitive value.
|
//! Query a value in a subtree with default primitive value.
|
||||||
/*!
|
/*!
|
||||||
\tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
||||||
@ -558,7 +563,7 @@ public:
|
|||||||
|
|
||||||
//! Query a value in a document with default primitive value.
|
//! Query a value in a document with default primitive value.
|
||||||
/*!
|
/*!
|
||||||
\tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
||||||
*/
|
*/
|
||||||
template <typename T, typename stackAllocator>
|
template <typename T, typename stackAllocator>
|
||||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
||||||
@ -604,7 +609,7 @@ public:
|
|||||||
|
|
||||||
//! Set a primitive value in a subtree.
|
//! Set a primitive value in a subtree.
|
||||||
/*!
|
/*!
|
||||||
\tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
||||||
@ -640,7 +645,7 @@ public:
|
|||||||
|
|
||||||
//! Set a primitive value in a document.
|
//! Set a primitive value in a document.
|
||||||
/*!
|
/*!
|
||||||
\tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
|
||||||
*/
|
*/
|
||||||
template <typename T, typename stackAllocator>
|
template <typename T, typename stackAllocator>
|
||||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
|
||||||
@ -762,11 +767,13 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Parse a JSON String or its URI fragment representation into tokens.
|
//! Parse a JSON String or its URI fragment representation into tokens.
|
||||||
|
#ifndef __clang__ // -Wdocumentation
|
||||||
/*!
|
/*!
|
||||||
\param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
|
\param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
|
||||||
\param length Length of the source string.
|
\param length Length of the source string.
|
||||||
\note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
|
\note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
|
||||||
*/
|
*/
|
||||||
|
#endif
|
||||||
void Parse(const Ch* source, size_t length) {
|
void Parse(const Ch* source, size_t length) {
|
||||||
RAPIDJSON_ASSERT(source != NULL);
|
RAPIDJSON_ASSERT(source != NULL);
|
||||||
RAPIDJSON_ASSERT(nameBuffer_ == 0);
|
RAPIDJSON_ASSERT(nameBuffer_ == 0);
|
||||||
@ -860,7 +867,7 @@ private:
|
|||||||
|
|
||||||
*name++ = c;
|
*name++ = c;
|
||||||
}
|
}
|
||||||
token->length = name - token->name;
|
token->length = static_cast<SizeType>(name - token->name);
|
||||||
if (token->length == 0)
|
if (token->length == 0)
|
||||||
isNumber = false;
|
isNumber = false;
|
||||||
*name++ = '\0'; // Null terminator
|
*name++ = '\0'; // Null terminator
|
||||||
@ -947,6 +954,8 @@ private:
|
|||||||
*/
|
*/
|
||||||
class PercentDecodeStream {
|
class PercentDecodeStream {
|
||||||
public:
|
public:
|
||||||
|
typedef typename ValueType::Ch Ch;
|
||||||
|
|
||||||
//! Constructor
|
//! Constructor
|
||||||
/*!
|
/*!
|
||||||
\param source Start of the stream
|
\param source Start of the stream
|
||||||
@ -976,7 +985,7 @@ private:
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Tell() const { return src_ - head_; }
|
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||||
bool IsValid() const { return valid_; }
|
bool IsValid() const { return valid_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1313,4 +1322,8 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_POINTER_H_
|
#endif // RAPIDJSON_POINTER_H_
|
||||||
|
@ -186,7 +186,7 @@ protected:
|
|||||||
|
|
||||||
void WriteIndent() {
|
void WriteIndent() {
|
||||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
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_;
|
Ch indentChar_;
|
||||||
|
@ -119,6 +119,31 @@
|
|||||||
#define RAPIDJSON_NAMESPACE_END }
|
#define RAPIDJSON_NAMESPACE_END }
|
||||||
#endif
|
#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
|
// RAPIDJSON_NO_INT64DEFINE
|
||||||
|
|
||||||
@ -153,9 +178,9 @@
|
|||||||
|
|
||||||
#ifndef RAPIDJSON_FORCEINLINE
|
#ifndef RAPIDJSON_FORCEINLINE
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
#if defined(_MSC_VER) && !defined(NDEBUG)
|
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||||
#define RAPIDJSON_FORCEINLINE __forceinline
|
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
|
#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
|
||||||
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
|
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_FORCEINLINE
|
#define RAPIDJSON_FORCEINLINE
|
||||||
@ -211,6 +236,8 @@
|
|||||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
# 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__)
|
# 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
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif defined(_MSC_VER) && defined(_M_ARM)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||||
# define RAPIDJSON_ENDIAN
|
# define RAPIDJSON_ENDIAN
|
||||||
# else
|
# else
|
||||||
@ -238,13 +265,13 @@
|
|||||||
\param x pointer to align
|
\param x pointer to align
|
||||||
|
|
||||||
Some machines require strict data alignment. Currently the default uses 4 bytes
|
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
|
#ifndef RAPIDJSON_ALIGN
|
||||||
#if RAPIDJSON_64BIT == 1
|
#if RAPIDJSON_64BIT == 1
|
||||||
#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)
|
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
|
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -349,7 +376,9 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
|
|
||||||
// Adopt from boost
|
// Adopt from boost
|
||||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||||
|
#ifndef __clang__
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
#endif
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||||
@ -365,7 +394,9 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
#else
|
#else
|
||||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __clang__
|
||||||
//!@endcond
|
//!@endcond
|
||||||
|
#endif
|
||||||
|
|
||||||
/*! \def RAPIDJSON_STATIC_ASSERT
|
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||||
\brief (Internal) macro to check for conditions at compile-time
|
\brief (Internal) macro to check for conditions at compile-time
|
||||||
@ -378,6 +409,35 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
|
||||||
|
|
||||||
|
//! Compiler branching hint for expression with high probability to be true.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\param x Boolean expression likely to be true.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_LIKELY
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_LIKELY(x) x
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Compiler branching hint for expression with low probability to be true.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\param x Boolean expression unlikely to be true.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_UNLIKELY
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_UNLIKELY(x) x
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
@ -554,11 +614,25 @@ struct StreamTraits {
|
|||||||
enum { copyOptimization = 0 };
|
enum { copyOptimization = 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Reserve n characters for writing to a stream.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutReserve(Stream& stream, size_t count) {
|
||||||
|
(void)stream;
|
||||||
|
(void)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Write character to a stream, presuming buffer is reserved.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
|
||||||
|
stream.Put(c);
|
||||||
|
}
|
||||||
|
|
||||||
//! Put N copies of a character to a stream.
|
//! Put N copies of a character to a stream.
|
||||||
template<typename Stream, typename Ch>
|
template<typename Stream, typename Ch>
|
||||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||||
|
PutReserve<Stream>(stream, n);
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
stream.Put(c);
|
PutUnsafe(stream, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -39,6 +39,12 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|||||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
@ -49,7 +55,7 @@ RAPIDJSON_DIAG_OFF(effc++)
|
|||||||
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
|
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
|
||||||
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
|
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||||
if (HasParseError()) { return value; } \
|
if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
#endif
|
#endif
|
||||||
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
|
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
|
||||||
@ -140,6 +146,7 @@ enum ParseFlag {
|
|||||||
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
|
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.
|
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).
|
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
|
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -262,7 +269,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|||||||
return p;
|
return p;
|
||||||
|
|
||||||
// 16-byte align to the next boundary
|
// 16-byte align to the next boundary
|
||||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
while (p != nextAligned)
|
while (p != nextAligned)
|
||||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||||
++p;
|
++p;
|
||||||
@ -271,11 +278,11 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|||||||
|
|
||||||
// The rest of string using SIMD
|
// The rest of string using SIMD
|
||||||
static const char whitespace[16] = " \n\r\t";
|
static const char whitespace[16] = " \n\r\t";
|
||||||
const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
|
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
|
||||||
|
|
||||||
for (;; p += 16) {
|
for (;; p += 16) {
|
||||||
const __m128i s = _mm_load_si128((const __m128i *)p);
|
const __m128i s = _mm_load_si128(reinterpret_cast<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 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
|
if (r != 0) { // some of characters is non-whitespace
|
||||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
@ -299,7 +306,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|||||||
return p;
|
return p;
|
||||||
|
|
||||||
// 16-byte align to the next boundary
|
// 16-byte align to the next boundary
|
||||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15);
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
while (p != nextAligned)
|
while (p != nextAligned)
|
||||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||||
++p;
|
++p;
|
||||||
@ -307,24 +314,22 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|||||||
return p;
|
return p;
|
||||||
|
|
||||||
// The rest of string
|
// The rest of string
|
||||||
static const char whitespaces[4][17] = {
|
#define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
|
||||||
" ",
|
static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
|
||||||
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
#undef C16
|
||||||
"\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 w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
|
||||||
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
|
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
|
||||||
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
|
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
|
||||||
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
|
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
|
||||||
|
|
||||||
for (;; p += 16) {
|
for (;; p += 16) {
|
||||||
const __m128i s = _mm_load_si128((const __m128i *)p);
|
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||||
__m128i x = _mm_cmpeq_epi8(s, w0);
|
__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, w1));
|
||||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
|
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
|
||||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
|
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
|
if (r != 0) { // some of characters may be non-whitespace
|
||||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
@ -398,9 +403,10 @@ public:
|
|||||||
|
|
||||||
ClearStackOnExit scope(*this);
|
ClearStackOnExit scope(*this);
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (is.Peek() == '\0') {
|
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
}
|
}
|
||||||
@ -409,9 +415,10 @@ public:
|
|||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
|
||||||
if (is.Peek() != '\0') {
|
if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
}
|
}
|
||||||
@ -462,52 +469,96 @@ private:
|
|||||||
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<unsigned parseFlags, typename InputStream>
|
||||||
|
void SkipWhitespaceAndComments(InputStream& is) {
|
||||||
|
SkipWhitespace(is);
|
||||||
|
|
||||||
|
if (parseFlags & kParseCommentsFlag) {
|
||||||
|
while (RAPIDJSON_UNLIKELY(is.Peek() == '/')) {
|
||||||
|
is.Take();
|
||||||
|
|
||||||
|
if (is.Peek() == '*') {
|
||||||
|
is.Take();
|
||||||
|
while (true) {
|
||||||
|
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
|
if (is.Take() == '*') {
|
||||||
|
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
|
if (is.Take() == '/')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (RAPIDJSON_LIKELY(is.Peek() == '/')) {
|
||||||
|
is.Take();
|
||||||
|
while (is.Peek() != '\0' && is.Take() != '\n') { }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
|
SkipWhitespace(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse object: { string : value, ... }
|
// Parse object: { string : value, ... }
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseObject(InputStream& is, Handler& handler) {
|
void ParseObject(InputStream& is, Handler& handler) {
|
||||||
RAPIDJSON_ASSERT(is.Peek() == '{');
|
RAPIDJSON_ASSERT(is.Peek() == '{');
|
||||||
is.Take(); // Skip '{'
|
is.Take(); // Skip '{'
|
||||||
|
|
||||||
if (!handler.StartObject())
|
if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == '}') {
|
if (is.Peek() == '}') {
|
||||||
is.Take();
|
is.Take();
|
||||||
if (!handler.EndObject(0)) // empty object
|
if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SizeType memberCount = 0;;) {
|
for (SizeType memberCount = 0;;) {
|
||||||
if (is.Peek() != '"')
|
if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||||
|
|
||||||
ParseString<parseFlags>(is, handler, true);
|
ParseString<parseFlags>(is, handler, true);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Take() != ':')
|
if (RAPIDJSON_UNLIKELY(is.Take() != ':'))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
ParseValue<parseFlags>(is, handler);
|
ParseValue<parseFlags>(is, handler);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
++memberCount;
|
++memberCount;
|
||||||
|
|
||||||
switch (is.Take()) {
|
switch (is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',':
|
||||||
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
if (!handler.EndObject(memberCount))
|
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
default:
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,14 +569,15 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == '[');
|
RAPIDJSON_ASSERT(is.Peek() == '[');
|
||||||
is.Take(); // Skip '['
|
is.Take(); // Skip '['
|
||||||
|
|
||||||
if (!handler.StartArray())
|
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == ']') {
|
if (is.Peek() == ']') {
|
||||||
is.Take();
|
is.Take();
|
||||||
if (!handler.EndArray(0)) // empty array
|
if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -535,15 +587,21 @@ private:
|
|||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
++elementCount;
|
++elementCount;
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
switch (is.Take()) {
|
switch (is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',':
|
||||||
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
break;
|
||||||
case ']':
|
case ']':
|
||||||
if (!handler.EndArray(elementCount))
|
if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
default:
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,8 +611,8 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 'n');
|
RAPIDJSON_ASSERT(is.Peek() == 'n');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') {
|
if (RAPIDJSON_LIKELY(is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')) {
|
||||||
if (!handler.Null())
|
if (RAPIDJSON_UNLIKELY(!handler.Null()))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -566,8 +624,8 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 't');
|
RAPIDJSON_ASSERT(is.Peek() == 't');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') {
|
if (RAPIDJSON_LIKELY(is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')) {
|
||||||
if (!handler.Bool(true))
|
if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -579,8 +637,8 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 'f');
|
RAPIDJSON_ASSERT(is.Peek() == 'f');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') {
|
if (RAPIDJSON_LIKELY(is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')) {
|
||||||
if (!handler.Bool(false))
|
if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -619,7 +677,14 @@ private:
|
|||||||
*stack_.template Push<Ch>() = c;
|
*stack_.template Push<Ch>() = c;
|
||||||
++length_;
|
++length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
|
||||||
|
length_ += count;
|
||||||
|
return stack_.template Push<Ch>(count);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Length() const { return length_; }
|
size_t Length() const { return length_; }
|
||||||
|
|
||||||
Ch* Pop() {
|
Ch* Pop() {
|
||||||
return stack_.template Pop<Ch>(length_);
|
return stack_.template Pop<Ch>(length_);
|
||||||
}
|
}
|
||||||
@ -638,6 +703,9 @@ private:
|
|||||||
internal::StreamLocalCopy<InputStream> copy(is);
|
internal::StreamLocalCopy<InputStream> copy(is);
|
||||||
InputStream& s(copy.s);
|
InputStream& s(copy.s);
|
||||||
|
|
||||||
|
RAPIDJSON_ASSERT(s.Peek() == '\"');
|
||||||
|
s.Take(); // Skip '\"'
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (parseFlags & kParseInsituFlag) {
|
if (parseFlags & kParseInsituFlag) {
|
||||||
typename InputStream::Ch *head = s.PutBegin();
|
typename InputStream::Ch *head = s.PutBegin();
|
||||||
@ -645,7 +713,7 @@ private:
|
|||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
size_t length = s.PutEnd(head) - 1;
|
size_t length = s.PutEnd(head) - 1;
|
||||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
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));
|
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -656,7 +724,7 @@ private:
|
|||||||
const typename TargetEncoding::Ch* const str = stackStream.Pop();
|
const typename TargetEncoding::Ch* const str = stackStream.Pop();
|
||||||
success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
|
success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
|
||||||
}
|
}
|
||||||
if (!success)
|
if (RAPIDJSON_UNLIKELY(!success))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,27 +744,27 @@ private:
|
|||||||
#undef Z16
|
#undef Z16
|
||||||
//!@endcond
|
//!@endcond
|
||||||
|
|
||||||
RAPIDJSON_ASSERT(is.Peek() == '\"');
|
|
||||||
is.Take(); // Skip '\"'
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
// Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
|
||||||
|
if (!(parseFlags & kParseValidateEncodingFlag))
|
||||||
|
ScanCopyUnescapedString(is, os);
|
||||||
|
|
||||||
Ch c = is.Peek();
|
Ch c = is.Peek();
|
||||||
if (c == '\\') { // Escape
|
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
||||||
is.Take();
|
is.Take();
|
||||||
Ch e = is.Take();
|
Ch e = is.Take();
|
||||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
|
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)]))
|
||||||
os.Put(escape[(unsigned char)e]);
|
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
||||||
}
|
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
||||||
else if (e == 'u') { // Unicode
|
|
||||||
unsigned codepoint = ParseHex4(is);
|
unsigned codepoint = ParseHex4(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
|
||||||
// Handle UTF-16 surrogate pair
|
// Handle UTF-16 surrogate pair
|
||||||
if (is.Take() != '\\' || is.Take() != 'u')
|
if (RAPIDJSON_UNLIKELY(is.Take() != '\\' || is.Take() != 'u'))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||||
unsigned codepoint2 = ParseHex4(is);
|
unsigned codepoint2 = ParseHex4(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
|
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||||
}
|
}
|
||||||
@ -705,24 +773,188 @@ private:
|
|||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||||
}
|
}
|
||||||
else if (c == '"') { // Closing double quote
|
else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
|
||||||
is.Take();
|
is.Take();
|
||||||
os.Put('\0'); // null-terminate the string
|
os.Put('\0'); // null-terminate the string
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (c == '\0')
|
else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
if (c == '\0')
|
||||||
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
else
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (parseFlags & kParseValidateEncodingFlag ?
|
if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
|
||||||
!Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
!Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
||||||
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))
|
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
|
||||||
|
// Do nothing for generic version
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||||
|
// StringStream -> StackStream<char>
|
||||||
|
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
|
||||||
|
const char* p = is.src_;
|
||||||
|
|
||||||
|
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||||
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
|
while (p != nextAligned)
|
||||||
|
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||||
|
is.src_ = p;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
os.Put(*p++);
|
||||||
|
|
||||||
|
// The rest of string using SIMD
|
||||||
|
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||||
|
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||||
|
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
|
||||||
|
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||||
|
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||||
|
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||||
|
|
||||||
|
for (;; p += 16) {
|
||||||
|
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||||
|
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||||
|
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||||
|
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||||
|
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||||
|
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||||
|
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||||
|
SizeType length;
|
||||||
|
#ifdef _MSC_VER // Find the index of first escaped
|
||||||
|
unsigned long offset;
|
||||||
|
_BitScanForward(&offset, r);
|
||||||
|
length = offset;
|
||||||
|
#else
|
||||||
|
length = static_cast<SizeType>(__builtin_ffs(r) - 1);
|
||||||
|
#endif
|
||||||
|
char* q = reinterpret_cast<char*>(os.Push(length));
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
q[i] = p[i];
|
||||||
|
|
||||||
|
p += length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
is.src_ = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsituStringStream -> InsituStringStream
|
||||||
|
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
|
||||||
|
RAPIDJSON_ASSERT(&is == &os);
|
||||||
|
(void)os;
|
||||||
|
|
||||||
|
if (is.src_ == is.dst_) {
|
||||||
|
SkipUnescapedString(is);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* p = is.src_;
|
||||||
|
char *q = is.dst_;
|
||||||
|
|
||||||
|
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||||
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
|
while (p != nextAligned)
|
||||||
|
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||||
|
is.src_ = p;
|
||||||
|
is.dst_ = q;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*q++ = *p++;
|
||||||
|
|
||||||
|
// The rest of string using SIMD
|
||||||
|
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||||
|
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||||
|
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
|
||||||
|
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||||
|
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||||
|
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||||
|
|
||||||
|
for (;; p += 16, q += 16) {
|
||||||
|
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||||
|
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||||
|
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||||
|
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||||
|
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||||
|
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||||
|
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||||
|
size_t length;
|
||||||
|
#ifdef _MSC_VER // Find the index of first escaped
|
||||||
|
unsigned long offset;
|
||||||
|
_BitScanForward(&offset, r);
|
||||||
|
length = offset;
|
||||||
|
#else
|
||||||
|
length = static_cast<size_t>(__builtin_ffs(r) - 1);
|
||||||
|
#endif
|
||||||
|
for (const char* pend = p + length; p != pend; )
|
||||||
|
*q++ = *p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
is.src_ = p;
|
||||||
|
is.dst_ = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When read/write pointers are the same for insitu stream, just skip unescaped characters
|
||||||
|
static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
|
||||||
|
RAPIDJSON_ASSERT(is.src_ == is.dst_);
|
||||||
|
char* p = is.src_;
|
||||||
|
|
||||||
|
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
|
||||||
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
|
for (; p != nextAligned; p++)
|
||||||
|
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
||||||
|
is.src_ = is.dst_ = p;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The rest of string using SIMD
|
||||||
|
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||||
|
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||||
|
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
|
||||||
|
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||||
|
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||||
|
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||||
|
|
||||||
|
for (;; p += 16) {
|
||||||
|
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||||
|
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||||
|
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||||
|
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||||
|
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||||
|
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||||
|
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||||
|
size_t length;
|
||||||
|
#ifdef _MSC_VER // Find the index of first escaped
|
||||||
|
unsigned long offset;
|
||||||
|
_BitScanForward(&offset, r);
|
||||||
|
length = offset;
|
||||||
|
#else
|
||||||
|
length = static_cast<size_t>(__builtin_ffs(r) - 1);
|
||||||
|
#endif
|
||||||
|
p += length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is.src_ = is.dst_ = p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename InputStream, bool backup>
|
template<typename InputStream, bool backup>
|
||||||
class NumberStream;
|
class NumberStream;
|
||||||
|
|
||||||
@ -753,7 +985,7 @@ private:
|
|||||||
~NumberStream() {}
|
~NumberStream() {}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
||||||
stackStream.Put((char)Base::is.Peek());
|
stackStream.Put(static_cast<char>(Base::is.Peek()));
|
||||||
return Base::is.Take();
|
return Base::is.Take();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -785,17 +1017,17 @@ private:
|
|||||||
uint64_t i64 = 0;
|
uint64_t i64 = 0;
|
||||||
bool use64bit = false;
|
bool use64bit = false;
|
||||||
int significandDigit = 0;
|
int significandDigit = 0;
|
||||||
if (s.Peek() == '0') {
|
if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
|
||||||
i = 0;
|
i = 0;
|
||||||
s.TakePush();
|
s.TakePush();
|
||||||
}
|
}
|
||||||
else if (s.Peek() >= '1' && s.Peek() <= '9') {
|
else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
|
||||||
i = static_cast<unsigned>(s.TakePush() - '0');
|
i = static_cast<unsigned>(s.TakePush() - '0');
|
||||||
|
|
||||||
if (minus)
|
if (minus)
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (i >= 214748364) { // 2^31 = 2147483648
|
if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
|
||||||
if (i != 214748364 || s.Peek() > '8') {
|
if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
|
||||||
i64 = i;
|
i64 = i;
|
||||||
use64bit = true;
|
use64bit = true;
|
||||||
break;
|
break;
|
||||||
@ -805,9 +1037,9 @@ private:
|
|||||||
significandDigit++;
|
significandDigit++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (i >= 429496729) { // 2^32 - 1 = 4294967295
|
if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
|
||||||
if (i != 429496729 || s.Peek() > '5') {
|
if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
|
||||||
i64 = i;
|
i64 = i;
|
||||||
use64bit = true;
|
use64bit = true;
|
||||||
break;
|
break;
|
||||||
@ -825,10 +1057,10 @@ private:
|
|||||||
double d = 0.0;
|
double d = 0.0;
|
||||||
if (use64bit) {
|
if (use64bit) {
|
||||||
if (minus)
|
if (minus)
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
|
if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
|
||||||
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
|
if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
|
||||||
d = i64;
|
d = static_cast<double>(i64);
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -836,10 +1068,10 @@ private:
|
|||||||
significandDigit++;
|
significandDigit++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
|
if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
|
||||||
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
|
if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
|
||||||
d = i64;
|
d = static_cast<double>(i64);
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -850,8 +1082,8 @@ private:
|
|||||||
|
|
||||||
// Force double for big integer
|
// Force double for big integer
|
||||||
if (useDouble) {
|
if (useDouble) {
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0
|
if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||||
d = d * 10 + (s.TakePush() - '0');
|
d = d * 10 + (s.TakePush() - '0');
|
||||||
}
|
}
|
||||||
@ -864,7 +1096,7 @@ private:
|
|||||||
s.Take();
|
s.Take();
|
||||||
decimalPosition = s.Length();
|
decimalPosition = s.Length();
|
||||||
|
|
||||||
if (!(s.Peek() >= '0' && s.Peek() <= '9'))
|
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
|
||||||
|
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
@ -873,7 +1105,7 @@ private:
|
|||||||
if (!use64bit)
|
if (!use64bit)
|
||||||
i64 = i;
|
i64 = i;
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
|
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
|
||||||
break;
|
break;
|
||||||
else {
|
else {
|
||||||
@ -884,19 +1116,19 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = (double)i64;
|
d = static_cast<double>(i64);
|
||||||
#else
|
#else
|
||||||
// Use double to store significand in 32-bit architecture
|
// Use double to store significand in 32-bit architecture
|
||||||
d = use64bit ? (double)i64 : (double)i;
|
d = static_cast<double>(use64bit ? i64 : i);
|
||||||
#endif
|
#endif
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (significandDigit < 17) {
|
if (significandDigit < 17) {
|
||||||
d = d * 10.0 + (s.TakePush() - '0');
|
d = d * 10.0 + (s.TakePush() - '0');
|
||||||
--expFrac;
|
--expFrac;
|
||||||
if (d > 0.0)
|
if (RAPIDJSON_LIKELY(d > 0.0))
|
||||||
significandDigit++;
|
significandDigit++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -910,7 +1142,7 @@ private:
|
|||||||
int exp = 0;
|
int exp = 0;
|
||||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
d = use64bit ? i64 : i;
|
d = static_cast<double>(use64bit ? i64 : i);
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
}
|
}
|
||||||
s.Take();
|
s.Take();
|
||||||
@ -923,22 +1155,22 @@ private:
|
|||||||
expMinus = true;
|
expMinus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = s.Take() - '0';
|
exp = static_cast<int>(s.Take() - '0');
|
||||||
if (expMinus) {
|
if (expMinus) {
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = exp * 10 + (s.Take() - '0');
|
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||||
if (exp >= 214748364) { // Issue #313: prevent overflow exponent
|
if (exp >= 214748364) { // Issue #313: prevent overflow exponent
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent
|
while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
|
||||||
s.Take();
|
s.Take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // positive exp
|
else { // positive exp
|
||||||
int maxExp = 308 - expFrac;
|
int maxExp = 308 - expFrac;
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = exp * 10 + (s.Take() - '0');
|
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||||
if (exp > maxExp)
|
if (RAPIDJSON_UNLIKELY(exp > maxExp))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -978,7 +1210,7 @@ private:
|
|||||||
cont = handler.Uint(i);
|
cont = handler.Uint(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cont)
|
if (RAPIDJSON_UNLIKELY(!cont))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,7 +1224,10 @@ private:
|
|||||||
case '"': ParseString<parseFlags>(is, handler); break;
|
case '"': ParseString<parseFlags>(is, handler); break;
|
||||||
case '{': ParseObject<parseFlags>(is, handler); break;
|
case '{': ParseObject<parseFlags>(is, handler); break;
|
||||||
case '[': ParseArray <parseFlags>(is, handler); break;
|
case '[': ParseArray <parseFlags>(is, handler); break;
|
||||||
default : ParseNumber<parseFlags>(is, handler);
|
default :
|
||||||
|
ParseNumber<parseFlags>(is, handler);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,11 +1254,11 @@ private:
|
|||||||
IterativeParsingArrayFinishState,
|
IterativeParsingArrayFinishState,
|
||||||
|
|
||||||
// Single value state
|
// Single value state
|
||||||
IterativeParsingValueState,
|
IterativeParsingValueState
|
||||||
|
|
||||||
cIterativeParsingStateCount
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
|
||||||
|
|
||||||
// Tokens
|
// Tokens
|
||||||
enum Token {
|
enum Token {
|
||||||
LeftBracketToken = 0,
|
LeftBracketToken = 0,
|
||||||
@ -1065,8 +1300,8 @@ private:
|
|||||||
#undef N16
|
#undef N16
|
||||||
//!@endcond
|
//!@endcond
|
||||||
|
|
||||||
if (sizeof(Ch) == 1 || unsigned(c) < 256)
|
if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
|
||||||
return (Token)tokenMap[(unsigned char)c];
|
return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
|
||||||
else
|
else
|
||||||
return NumberToken;
|
return NumberToken;
|
||||||
}
|
}
|
||||||
@ -1232,7 +1467,7 @@ private:
|
|||||||
}
|
}
|
||||||
}; // End of G
|
}; // 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().
|
// Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
|
||||||
@ -1394,7 +1629,7 @@ private:
|
|||||||
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
|
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
|
||||||
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
|
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
|
||||||
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
|
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
|
||||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1404,7 +1639,8 @@ private:
|
|||||||
ClearStackOnExit scope(*this);
|
ClearStackOnExit scope(*this);
|
||||||
IterativeParsingState state = IterativeParsingStartState;
|
IterativeParsingState state = IterativeParsingStartState;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
while (is.Peek() != '\0') {
|
while (is.Peek() != '\0') {
|
||||||
Token t = Tokenize(is.Peek());
|
Token t = Tokenize(is.Peek());
|
||||||
IterativeParsingState n = Predict(state, t);
|
IterativeParsingState n = Predict(state, t);
|
||||||
@ -1421,7 +1657,8 @@ private:
|
|||||||
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the end of file.
|
// Handle the end of file.
|
||||||
@ -1441,6 +1678,11 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
|
|
||||||
#include "internal/stack.h"
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! Represents an in-memory output stream.
|
//! Represents an in-memory output stream.
|
||||||
@ -48,6 +53,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||||
|
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||||
void Flush() {}
|
void Flush() {}
|
||||||
|
|
||||||
void Clear() { stack_.Clear(); }
|
void Clear() { stack_.Clear(); }
|
||||||
@ -57,6 +63,8 @@ public:
|
|||||||
stack_.ShrinkToFit();
|
stack_.ShrinkToFit();
|
||||||
stack_.template Pop<Ch>(1);
|
stack_.template Pop<Ch>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||||
|
|
||||||
@ -82,6 +90,16 @@ private:
|
|||||||
//! String buffer with UTF8 encoding
|
//! String buffer with UTF8 encoding
|
||||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||||
|
|
||||||
|
template<typename Encoding, typename Allocator>
|
||||||
|
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||||
|
stream.Reserve(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Encoding, typename Allocator>
|
||||||
|
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||||
|
stream.PutUnsafe(c);
|
||||||
|
}
|
||||||
|
|
||||||
//! Implement specialized version of PutN() with memset() for better performance.
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
template<>
|
template<>
|
||||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||||
@ -90,4 +108,8 @@ inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
|||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||||
|
@ -23,15 +23,16 @@
|
|||||||
#include "stringbuffer.h"
|
#include "stringbuffer.h"
|
||||||
#include <new> // placement new
|
#include <new> // placement new
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
|
||||||
#include <string>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
//! JSON writer
|
//! JSON writer
|
||||||
@ -145,7 +146,7 @@ public:
|
|||||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||||
level_stack_.template Pop<Level>(1);
|
level_stack_.template Pop<Level>(1);
|
||||||
bool ret = WriteEndObject();
|
bool ret = WriteEndObject();
|
||||||
if (level_stack_.Empty()) // end of json text
|
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
|
||||||
os_->Flush();
|
os_->Flush();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -162,7 +163,7 @@ public:
|
|||||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||||
level_stack_.template Pop<Level>(1);
|
level_stack_.template Pop<Level>(1);
|
||||||
bool ret = WriteEndArray();
|
bool ret = WriteEndArray();
|
||||||
if (level_stack_.Empty()) // end of json text
|
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
|
||||||
os_->Flush();
|
os_->Flush();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -188,15 +189,18 @@ protected:
|
|||||||
static const size_t kDefaultLevelDepth = 32;
|
static const size_t kDefaultLevelDepth = 32;
|
||||||
|
|
||||||
bool WriteNull() {
|
bool WriteNull() {
|
||||||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
|
PutReserve(*os_, 4);
|
||||||
|
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteBool(bool b) {
|
bool WriteBool(bool b) {
|
||||||
if (b) {
|
if (b) {
|
||||||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
|
PutReserve(*os_, 4);
|
||||||
|
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
|
PutReserve(*os_, 5);
|
||||||
|
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -204,45 +208,50 @@ protected:
|
|||||||
bool WriteInt(int i) {
|
bool WriteInt(int i) {
|
||||||
char buffer[11];
|
char buffer[11];
|
||||||
const char* end = internal::i32toa(i, buffer);
|
const char* end = internal::i32toa(i, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
for (const char* p = buffer; p != end; ++p)
|
for (const char* p = buffer; p != end; ++p)
|
||||||
os_->Put(*p);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteUint(unsigned u) {
|
bool WriteUint(unsigned u) {
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
const char* end = internal::u32toa(u, buffer);
|
const char* end = internal::u32toa(u, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
for (const char* p = buffer; p != end; ++p)
|
for (const char* p = buffer; p != end; ++p)
|
||||||
os_->Put(*p);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteInt64(int64_t i64) {
|
bool WriteInt64(int64_t i64) {
|
||||||
char buffer[21];
|
char buffer[21];
|
||||||
const char* end = internal::i64toa(i64, buffer);
|
const char* end = internal::i64toa(i64, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
for (const char* p = buffer; p != end; ++p)
|
for (const char* p = buffer; p != end; ++p)
|
||||||
os_->Put(*p);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteUint64(uint64_t u64) {
|
bool WriteUint64(uint64_t u64) {
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
char* end = internal::u64toa(u64, buffer);
|
char* end = internal::u64toa(u64, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
for (char* p = buffer; p != end; ++p)
|
for (char* p = buffer; p != end; ++p)
|
||||||
os_->Put(*p);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteDouble(double d) {
|
bool WriteDouble(double d) {
|
||||||
char buffer[25];
|
char buffer[25];
|
||||||
char* end = internal::dtoa(d, buffer);
|
char* end = internal::dtoa(d, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
for (char* p = buffer; p != end; ++p)
|
for (char* p = buffer; p != end; ++p)
|
||||||
os_->Put(*p);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteString(const Ch* str, SizeType length) {
|
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] = {
|
static const char escape[256] = {
|
||||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
#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
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
@ -255,22 +264,27 @@ protected:
|
|||||||
#undef Z16
|
#undef Z16
|
||||||
};
|
};
|
||||||
|
|
||||||
os_->Put('\"');
|
if (TargetEncoding::supportUnicode)
|
||||||
|
PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
|
||||||
|
else
|
||||||
|
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
|
||||||
|
|
||||||
|
PutUnsafe(*os_, '\"');
|
||||||
GenericStringStream<SourceEncoding> is(str);
|
GenericStringStream<SourceEncoding> is(str);
|
||||||
while (is.Tell() < length) {
|
while (RAPIDJSON_LIKELY(is.Tell() < length)) {
|
||||||
const Ch c = is.Peek();
|
const Ch c = is.Peek();
|
||||||
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
|
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
|
||||||
// Unicode escaping
|
// Unicode escaping
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
if (!SourceEncoding::Decode(is, &codepoint))
|
if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
|
||||||
return false;
|
return false;
|
||||||
os_->Put('\\');
|
PutUnsafe(*os_, '\\');
|
||||||
os_->Put('u');
|
PutUnsafe(*os_, 'u');
|
||||||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||||
os_->Put(hexDigits[(codepoint >> 12) & 15]);
|
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
|
||||||
os_->Put(hexDigits[(codepoint >> 8) & 15]);
|
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
|
||||||
os_->Put(hexDigits[(codepoint >> 4) & 15]);
|
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
|
||||||
os_->Put(hexDigits[(codepoint ) & 15]);
|
PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
|
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
|
||||||
@ -278,34 +292,34 @@ protected:
|
|||||||
unsigned s = codepoint - 0x010000;
|
unsigned s = codepoint - 0x010000;
|
||||||
unsigned lead = (s >> 10) + 0xD800;
|
unsigned lead = (s >> 10) + 0xD800;
|
||||||
unsigned trail = (s & 0x3FF) + 0xDC00;
|
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||||
os_->Put(hexDigits[(lead >> 12) & 15]);
|
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
|
||||||
os_->Put(hexDigits[(lead >> 8) & 15]);
|
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
|
||||||
os_->Put(hexDigits[(lead >> 4) & 15]);
|
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
|
||||||
os_->Put(hexDigits[(lead ) & 15]);
|
PutUnsafe(*os_, hexDigits[(lead ) & 15]);
|
||||||
os_->Put('\\');
|
PutUnsafe(*os_, '\\');
|
||||||
os_->Put('u');
|
PutUnsafe(*os_, 'u');
|
||||||
os_->Put(hexDigits[(trail >> 12) & 15]);
|
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
|
||||||
os_->Put(hexDigits[(trail >> 8) & 15]);
|
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
|
||||||
os_->Put(hexDigits[(trail >> 4) & 15]);
|
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
|
||||||
os_->Put(hexDigits[(trail ) & 15]);
|
PutUnsafe(*os_, 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) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
|
||||||
is.Take();
|
is.Take();
|
||||||
os_->Put('\\');
|
PutUnsafe(*os_, '\\');
|
||||||
os_->Put(escape[(unsigned char)c]);
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
|
||||||
if (escape[(unsigned char)c] == 'u') {
|
if (escape[static_cast<unsigned char>(c)] == 'u') {
|
||||||
os_->Put('0');
|
PutUnsafe(*os_, '0');
|
||||||
os_->Put('0');
|
PutUnsafe(*os_, '0');
|
||||||
os_->Put(hexDigits[(unsigned char)c >> 4]);
|
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
|
||||||
os_->Put(hexDigits[(unsigned char)c & 0xF]);
|
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
|
if (RAPIDJSON_UNLIKELY(!(Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
os_->Put('\"');
|
PutUnsafe(*os_, '\"');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +330,7 @@ protected:
|
|||||||
|
|
||||||
void Prefix(Type type) {
|
void Prefix(Type type) {
|
||||||
(void)type;
|
(void)type;
|
||||||
if (level_stack_.GetSize() != 0) { // this value is not at root
|
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
|
||||||
Level* level = level_stack_.template Top<Level>();
|
Level* level = level_stack_.template Top<Level>();
|
||||||
if (level->valueCount > 0) {
|
if (level->valueCount > 0) {
|
||||||
if (level->inArray)
|
if (level->inArray)
|
||||||
@ -392,4 +406,8 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||||
|
75
rapidjson.autopkg
Normal file
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;
|
||||||
|
};
|
||||||
|
}
|
14
readme.md
14
readme.md
@ -31,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 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).
|
More features can be read [here](doc/features.md).
|
||||||
|
|
||||||
@ -63,9 +63,9 @@ Users can build and run the unit tests on their platform/compiler.
|
|||||||
RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
|
RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
|
||||||
|
|
||||||
RapidJSON uses following software as its dependencies:
|
RapidJSON uses following software as its dependencies:
|
||||||
* [CMake](http://www.cmake.org) as a general build tool
|
* [CMake](https://cmake.org/) as a general build tool
|
||||||
* (optional)[Doxygen](http://www.doxygen.org) to build documentation
|
* (optional)[Doxygen](http://www.doxygen.org) to build documentation
|
||||||
* (optional)[googletest](https://code.google.com/p/googletest/) for unit and performance testing
|
* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing
|
||||||
|
|
||||||
To generate user documentation and run tests please proceed with the steps below:
|
To generate user documentation and run tests please proceed with the steps below:
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ IF(GTESTSRC_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(${GTEST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/googletest)
|
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)
|
set(TEST_LIBRARIES gtest gtest_main)
|
||||||
|
|
||||||
|
@ -65,44 +65,87 @@ public:
|
|||||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
|
{
|
||||||
|
const char *paths[] = {
|
||||||
|
"data/sample.json",
|
||||||
|
"bin/data/sample.json",
|
||||||
|
"../bin/data/sample.json",
|
||||||
|
"../../bin/data/sample.json",
|
||||||
|
"../../../bin/data/sample.json"
|
||||||
|
};
|
||||||
|
|
||||||
const char *paths[] = {
|
FILE *fp = 0;
|
||||||
"data/sample.json",
|
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||||
"bin/data/sample.json",
|
fp = fopen(filename_ = paths[i], "rb");
|
||||||
"../bin/data/sample.json",
|
if (fp)
|
||||||
"../../bin/data/sample.json",
|
break;
|
||||||
"../../../bin/data/sample.json"
|
}
|
||||||
};
|
ASSERT_TRUE(fp != 0);
|
||||||
FILE *fp = 0;
|
|
||||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
fseek(fp, 0, SEEK_END);
|
||||||
fp = fopen(filename_ = paths[i], "rb");
|
length_ = (size_t)ftell(fp);
|
||||||
if (fp)
|
fseek(fp, 0, SEEK_SET);
|
||||||
break;
|
json_ = (char*)malloc(length_ + 1);
|
||||||
|
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
||||||
|
json_[length_] = '\0';
|
||||||
|
fclose(fp);
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(fp != 0);
|
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
length_ = (size_t)ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
json_ = (char*)malloc(length_ + 1);
|
|
||||||
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
|
||||||
json_[length_] = '\0';
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
// whitespace test
|
// whitespace test
|
||||||
whitespace_length_ = 1024 * 1024;
|
{
|
||||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
whitespace_length_ = 1024 * 1024;
|
||||||
char *p = whitespace_;
|
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
char *p = whitespace_;
|
||||||
*p++ = ' ';
|
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||||
*p++ = '\n';
|
*p++ = ' ';
|
||||||
*p++ = '\r';
|
*p++ = '\n';
|
||||||
*p++ = '\t';
|
*p++ = '\r';
|
||||||
|
*p++ = '\t';
|
||||||
|
}
|
||||||
|
*p++ = '[';
|
||||||
|
*p++ = '0';
|
||||||
|
*p++ = ']';
|
||||||
|
*p++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// types test
|
||||||
|
{
|
||||||
|
const char *typespaths[] = {
|
||||||
|
"data/types",
|
||||||
|
"bin/types",
|
||||||
|
"../bin/types",
|
||||||
|
"../../bin/types/",
|
||||||
|
"../../../bin/types"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* typesfilenames[] = {
|
||||||
|
"booleans.json",
|
||||||
|
"floats.json",
|
||||||
|
"guids.json",
|
||||||
|
"integers.json",
|
||||||
|
"mixed.json",
|
||||||
|
"nulls.json",
|
||||||
|
"paragraphs.json"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
|
||||||
|
types_[j] = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(typespaths) / sizeof(typespaths[0]); i++) {
|
||||||
|
char filename[256];
|
||||||
|
sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]);
|
||||||
|
if (FILE* fp = fopen(filename, "rb")) {
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
typesLength_[j] = (size_t)ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
types_[j] = (char*)malloc(typesLength_[j] + 1);
|
||||||
|
ASSERT_EQ(typesLength_[j], fread(types_[j], 1, typesLength_[j], fp));
|
||||||
|
types_[j][typesLength_[j]] = '\0';
|
||||||
|
fclose(fp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*p++ = '[';
|
|
||||||
*p++ = '0';
|
|
||||||
*p++ = ']';
|
|
||||||
*p++ = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
@ -110,6 +153,10 @@ public:
|
|||||||
free(whitespace_);
|
free(whitespace_);
|
||||||
json_ = 0;
|
json_ = 0;
|
||||||
whitespace_ = 0;
|
whitespace_ = 0;
|
||||||
|
for (size_t i = 0; i < 7; i++) {
|
||||||
|
free(types_[i]);
|
||||||
|
types_[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -122,6 +169,8 @@ protected:
|
|||||||
size_t length_;
|
size_t length_;
|
||||||
char *whitespace_;
|
char *whitespace_;
|
||||||
size_t whitespace_length_;
|
size_t whitespace_length_;
|
||||||
|
char *types_[7];
|
||||||
|
size_t typesLength_[7];
|
||||||
|
|
||||||
static const size_t kTrialCount = 1000;
|
static const size_t kTrialCount = 1000;
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,10 @@ public:
|
|||||||
temp_ = (char *)malloc(length_ + 1);
|
temp_ = (char *)malloc(length_ + 1);
|
||||||
|
|
||||||
// Parse as a document
|
// Parse as a document
|
||||||
EXPECT_FALSE(doc_.Parse(json_).IsNull());
|
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 7; i++)
|
||||||
|
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
@ -60,6 +63,7 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
char *temp_;
|
char *temp_;
|
||||||
Document doc_;
|
Document doc_;
|
||||||
|
Document typesDoc_[7];
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
|
||||||
@ -91,6 +95,35 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TEST_TYPED(index, Name)\
|
||||||
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_##Name)) {\
|
||||||
|
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||||
|
StringStream s(types_[index]);\
|
||||||
|
BaseReaderHandler<> h;\
|
||||||
|
Reader reader;\
|
||||||
|
EXPECT_TRUE(reader.Parse(s, h));\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_##Name)) {\
|
||||||
|
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||||
|
memcpy(temp_, types_[index], typesLength_[index] + 1);\
|
||||||
|
InsituStringStream s(temp_);\
|
||||||
|
BaseReaderHandler<> h;\
|
||||||
|
Reader reader;\
|
||||||
|
EXPECT_TRUE(reader.Parse<kParseInsituFlag>(s, h));\
|
||||||
|
}\
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_TYPED(0, Booleans)
|
||||||
|
TEST_TYPED(1, Floats)
|
||||||
|
TEST_TYPED(2, Guids)
|
||||||
|
TEST_TYPED(3, Integers)
|
||||||
|
TEST_TYPED(4, Mixed)
|
||||||
|
TEST_TYPED(5, Nulls)
|
||||||
|
TEST_TYPED(6, Paragraphs)
|
||||||
|
|
||||||
|
#undef TEST_TYPED
|
||||||
|
|
||||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
|
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
|
||||||
for (size_t i = 0; i < kTrialCount; i++) {
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
StringStream s(json_);
|
StringStream s(json_);
|
||||||
@ -250,8 +283,10 @@ TEST_F(RapidJson, DocumentAccept) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct NullStream {
|
struct NullStream {
|
||||||
|
typedef char Ch;
|
||||||
|
|
||||||
NullStream() /*: length_(0)*/ {}
|
NullStream() /*: length_(0)*/ {}
|
||||||
void Put(char) { /*++length_;*/ }
|
void Put(Ch) { /*++length_;*/ }
|
||||||
void Flush() {}
|
void Flush() {}
|
||||||
//size_t length_;
|
//size_t length_;
|
||||||
};
|
};
|
||||||
@ -278,6 +313,27 @@ TEST_F(RapidJson, Writer_StringBuffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TEST_TYPED(index, Name)\
|
||||||
|
TEST_F(RapidJson, Writer_StringBuffer_##Name) {\
|
||||||
|
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||||
|
StringBuffer s(0, 1024 * 1024);\
|
||||||
|
Writer<StringBuffer> writer(s);\
|
||||||
|
typesDoc_[index].Accept(writer);\
|
||||||
|
const char* str = s.GetString();\
|
||||||
|
(void)str;\
|
||||||
|
}\
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_TYPED(0, Booleans)
|
||||||
|
TEST_TYPED(1, Floats)
|
||||||
|
TEST_TYPED(2, Guids)
|
||||||
|
TEST_TYPED(3, Integers)
|
||||||
|
TEST_TYPED(4, Mixed)
|
||||||
|
TEST_TYPED(5, Nulls)
|
||||||
|
TEST_TYPED(6, Paragraphs)
|
||||||
|
|
||||||
|
#undef TEST_TYPED
|
||||||
|
|
||||||
TEST_F(RapidJson, PrettyWriter_StringBuffer) {
|
TEST_F(RapidJson, PrettyWriter_StringBuffer) {
|
||||||
for (size_t i = 0; i < kTrialCount; i++) {
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
StringBuffer s(0, 2048 * 1024);
|
StringBuffer s(0, 2048 * 1024);
|
||||||
@ -357,4 +413,10 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RapidJson, StringBuffer) {
|
||||||
|
StringBuffer sb;
|
||||||
|
for (int i = 0; i < 32 * 1024 * 1024; i++)
|
||||||
|
sb.Put(i & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TEST_RAPIDJSON
|
#endif // TEST_RAPIDJSON
|
||||||
|
@ -24,7 +24,7 @@ set(UNITTEST_SOURCES
|
|||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough")
|
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")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||||
endif()
|
endif()
|
||||||
|
@ -22,21 +22,21 @@ template <typename Allocator>
|
|||||||
void TestAllocator(Allocator& a) {
|
void TestAllocator(Allocator& a) {
|
||||||
EXPECT_TRUE(a.Malloc(0) == 0);
|
EXPECT_TRUE(a.Malloc(0) == 0);
|
||||||
|
|
||||||
uint8_t* p = (uint8_t*)a.Malloc(100);
|
uint8_t* p = static_cast<uint8_t*>(a.Malloc(100));
|
||||||
EXPECT_TRUE(p != 0);
|
EXPECT_TRUE(p != 0);
|
||||||
for (size_t i = 0; i < 100; i++)
|
for (size_t i = 0; i < 100; i++)
|
||||||
p[i] = (uint8_t)i;
|
p[i] = static_cast<uint8_t>(i);
|
||||||
|
|
||||||
// Expand
|
// 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);
|
EXPECT_TRUE(q != 0);
|
||||||
for (size_t i = 0; i < 100; i++)
|
for (size_t i = 0; i < 100; i++)
|
||||||
EXPECT_EQ(i, q[i]);
|
EXPECT_EQ(i, q[i]);
|
||||||
for (size_t i = 100; i < 200; i++)
|
for (size_t i = 100; i < 200; i++)
|
||||||
q[i] = (uint8_t)i;
|
q[i] = static_cast<uint8_t>(i);
|
||||||
|
|
||||||
// Shrink
|
// 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);
|
EXPECT_TRUE(r != 0);
|
||||||
for (size_t i = 0; i < 150; i++)
|
for (size_t i = 0; i < 150; i++)
|
||||||
EXPECT_EQ(i, r[i]);
|
EXPECT_EQ(i, r[i]);
|
||||||
@ -56,8 +56,28 @@ TEST(Allocator, MemoryPoolAllocator) {
|
|||||||
MemoryPoolAllocator<> a;
|
MemoryPoolAllocator<> a;
|
||||||
TestAllocator(a);
|
TestAllocator(a);
|
||||||
|
|
||||||
for (int i = 1; i < 1000; i++) {
|
for (size_t i = 1; i < 1000; i++) {
|
||||||
EXPECT_TRUE(a.Malloc(i) != 0);
|
EXPECT_TRUE(a.Malloc(i) != 0);
|
||||||
EXPECT_LE(a.Size(), a.Capacity());
|
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
|
||||||
|
}
|
||||||
|
@ -21,6 +21,12 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-variable-declarations)
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
template <typename DocumentType>
|
template <typename DocumentType>
|
||||||
@ -28,6 +34,7 @@ void ParseCheck(DocumentType& doc) {
|
|||||||
typedef typename DocumentType::ValueType ValueType;
|
typedef typename DocumentType::ValueType ValueType;
|
||||||
|
|
||||||
EXPECT_FALSE(doc.HasParseError());
|
EXPECT_FALSE(doc.HasParseError());
|
||||||
|
EXPECT_TRUE(static_cast<ParseResult>(doc));
|
||||||
|
|
||||||
EXPECT_TRUE(doc.IsObject());
|
EXPECT_TRUE(doc.IsObject());
|
||||||
|
|
||||||
@ -62,8 +69,8 @@ void ParseCheck(DocumentType& doc) {
|
|||||||
const ValueType& a = doc["a"];
|
const ValueType& a = doc["a"];
|
||||||
EXPECT_TRUE(a.IsArray());
|
EXPECT_TRUE(a.IsArray());
|
||||||
EXPECT_EQ(4u, a.Size());
|
EXPECT_EQ(4u, a.Size());
|
||||||
for (SizeType i = 0; i < 4; i++)
|
for (SizeType j = 0; j < 4; j++)
|
||||||
EXPECT_EQ(i + 1, a[i].GetUint());
|
EXPECT_EQ(j + 1, a[j].GetUint());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Allocator, typename StackAllocator>
|
template <typename Allocator, typename StackAllocator>
|
||||||
@ -95,17 +102,37 @@ TEST(Document, Parse) {
|
|||||||
ParseTest<CrtAllocator, CrtAllocator>();
|
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) {
|
static FILE* OpenEncodedFile(const char* filename) {
|
||||||
const char *paths[] = {
|
const char *paths[] = {
|
||||||
"encodings/%s",
|
"encodings",
|
||||||
"bin/encodings/%s",
|
"bin/encodings",
|
||||||
"../bin/encodings/%s",
|
"../bin/encodings",
|
||||||
"../../bin/encodings/%s",
|
"../../bin/encodings",
|
||||||
"../../../bin/encodings/%s"
|
"../../../bin/encodings"
|
||||||
};
|
};
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
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");
|
FILE *fp = fopen(buffer, "rb");
|
||||||
if (fp)
|
if (fp)
|
||||||
return fp;
|
return fp;
|
||||||
@ -136,22 +163,22 @@ TEST(Document, ParseStream_EncodedInputStream) {
|
|||||||
StringBuffer bos;
|
StringBuffer bos;
|
||||||
typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
|
typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
|
||||||
OutputStream eos(bos, false); // Not writing BOM
|
OutputStream eos(bos, false); // Not writing BOM
|
||||||
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
|
|
||||||
d.Accept(writer);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Condense the original file and compare.
|
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
|
||||||
FILE *fp = OpenEncodedFile("utf8.json");
|
d.Accept(writer);
|
||||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
|
||||||
Reader reader;
|
|
||||||
StringBuffer bos2;
|
|
||||||
Writer<StringBuffer> writer(bos2);
|
|
||||||
reader.Parse(is, writer);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
|
||||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
TEST(Document, ParseStream_AutoUTFInputStream) {
|
||||||
@ -178,19 +205,17 @@ TEST(Document, ParseStream_AutoUTFInputStream) {
|
|||||||
Writer<StringBuffer> writer(bos);
|
Writer<StringBuffer> writer(bos);
|
||||||
d.Accept(writer);
|
d.Accept(writer);
|
||||||
|
|
||||||
{
|
// Condense the original file and compare.
|
||||||
// Condense the original file and compare.
|
fp = OpenEncodedFile("utf8.json");
|
||||||
FILE *fp = OpenEncodedFile("utf8.json");
|
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
Reader reader;
|
||||||
Reader reader;
|
StringBuffer bos2;
|
||||||
StringBuffer bos2;
|
Writer<StringBuffer> writer2(bos2);
|
||||||
Writer<StringBuffer> writer(bos2);
|
reader.Parse(is, writer2);
|
||||||
reader.Parse(is, writer);
|
fclose(fp);
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Document, Swap) {
|
TEST(Document, Swap) {
|
||||||
@ -242,12 +267,16 @@ TEST(Document, Swap) {
|
|||||||
struct OutputStringStream : public std::ostringstream {
|
struct OutputStringStream : public std::ostringstream {
|
||||||
typedef char Ch;
|
typedef char Ch;
|
||||||
|
|
||||||
|
virtual ~OutputStringStream();
|
||||||
|
|
||||||
void Put(char c) {
|
void Put(char c) {
|
||||||
put(c);
|
put(c);
|
||||||
}
|
}
|
||||||
void Flush() {}
|
void Flush() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OutputStringStream::~OutputStringStream() {}
|
||||||
|
|
||||||
TEST(Document, AcceptWriter) {
|
TEST(Document, AcceptWriter) {
|
||||||
Document doc;
|
Document doc;
|
||||||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||||
@ -305,6 +334,8 @@ TEST(Document, UTF16_Document) {
|
|||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#if 0 // Many old compiler does not support these. Turn it off temporaily.
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
TEST(Document, Traits) {
|
TEST(Document, Traits) {
|
||||||
@ -342,6 +373,8 @@ TEST(Document, Traits) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename Allocator>
|
template <typename Allocator>
|
||||||
struct DocumentMove: public ::testing::Test {
|
struct DocumentMove: public ::testing::Test {
|
||||||
};
|
};
|
||||||
@ -366,7 +399,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) {
|
|||||||
EXPECT_TRUE(a.IsNull());
|
EXPECT_TRUE(a.IsNull());
|
||||||
EXPECT_TRUE(b.IsArray());
|
EXPECT_TRUE(b.IsArray());
|
||||||
EXPECT_EQ(3u, b.Size());
|
EXPECT_EQ(3u, b.Size());
|
||||||
EXPECT_EQ(&a.GetAllocator(), (void*)0);
|
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||||
|
|
||||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||||
@ -379,7 +412,7 @@ TYPED_TEST(DocumentMove, MoveConstructor) {
|
|||||||
EXPECT_TRUE(b.IsNull());
|
EXPECT_TRUE(b.IsNull());
|
||||||
EXPECT_TRUE(c.IsObject());
|
EXPECT_TRUE(c.IsObject());
|
||||||
EXPECT_EQ(2u, c.MemberCount());
|
EXPECT_EQ(2u, c.MemberCount());
|
||||||
EXPECT_EQ(&b.GetAllocator(), (void*)0);
|
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +493,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) {
|
|||||||
EXPECT_TRUE(a.IsNull());
|
EXPECT_TRUE(a.IsNull());
|
||||||
EXPECT_TRUE(b.IsArray());
|
EXPECT_TRUE(b.IsArray());
|
||||||
EXPECT_EQ(3u, b.Size());
|
EXPECT_EQ(3u, b.Size());
|
||||||
EXPECT_EQ(&a.GetAllocator(), (void*)0);
|
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||||
|
|
||||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||||
@ -474,7 +507,7 @@ TYPED_TEST(DocumentMove, MoveAssignment) {
|
|||||||
EXPECT_TRUE(b.IsNull());
|
EXPECT_TRUE(b.IsNull());
|
||||||
EXPECT_TRUE(c.IsObject());
|
EXPECT_TRUE(c.IsObject());
|
||||||
EXPECT_EQ(2u, c.MemberCount());
|
EXPECT_EQ(2u, c.MemberCount());
|
||||||
EXPECT_EQ(&b.GetAllocator(), (void*)0);
|
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,3 +583,7 @@ TYPED_TEST(DocumentMove, MoveAssignmentStack) {
|
|||||||
// Document d2;
|
// Document d2;
|
||||||
// d1 = d2;
|
// d1 = d2;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
@ -25,6 +25,7 @@ using namespace rapidjson;
|
|||||||
class EncodedStreamTest : public ::testing::Test {
|
class EncodedStreamTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
EncodedStreamTest() : json_(), length_() {}
|
EncodedStreamTest() : json_(), length_() {}
|
||||||
|
virtual ~EncodedStreamTest();
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
json_ = ReadFile("utf8.json", true, &length_);
|
json_ = ReadFile("utf8.json", true, &length_);
|
||||||
@ -42,15 +43,15 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
static FILE* Open(const char* filename) {
|
static FILE* Open(const char* filename) {
|
||||||
const char *paths[] = {
|
const char *paths[] = {
|
||||||
"encodings/%s",
|
"encodings",
|
||||||
"bin/encodings/%s",
|
"bin/encodings",
|
||||||
"../bin/encodings/%s",
|
"../bin/encodings",
|
||||||
"../../bin/encodings/%s",
|
"../../bin/encodings",
|
||||||
"../../../bin/encodings/%s"
|
"../../../bin/encodings"
|
||||||
};
|
};
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
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");
|
FILE *fp = fopen(buffer, "rb");
|
||||||
if (fp)
|
if (fp)
|
||||||
return fp;
|
return fp;
|
||||||
@ -67,9 +68,9 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
*outLength = (size_t)ftell(fp);
|
*outLength = static_cast<size_t>(ftell(fp));
|
||||||
fseek(fp, 0, SEEK_SET);
|
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);
|
size_t readLength = fread(buffer, 1, *outLength, fp);
|
||||||
buffer[readLength] = '\0';
|
buffer[readLength] = '\0';
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -248,6 +249,8 @@ protected:
|
|||||||
size_t length_;
|
size_t length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EncodedStreamTest::~EncodedStreamTest() {}
|
||||||
|
|
||||||
TEST_F(EncodedStreamTest, EncodedInputStream) {
|
TEST_F(EncodedStreamTest, EncodedInputStream) {
|
||||||
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8.json");
|
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8.json");
|
||||||
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
|
TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
|
||||||
|
@ -240,7 +240,6 @@ static const unsigned kCodepointRanges[] = {
|
|||||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||||
|
|
||||||
#define UTF8_ACCEPT 0u
|
#define UTF8_ACCEPT 0u
|
||||||
#define UTF8_REJECT 12u
|
|
||||||
|
|
||||||
static const unsigned char utf8d[] = {
|
static const unsigned char utf8d[] = {
|
||||||
// The first part of the table maps bytes to character classes that
|
// The first part of the table maps bytes to character classes that
|
||||||
@ -298,7 +297,7 @@ TEST(EncodingsTest, UTF8) {
|
|||||||
|
|
||||||
unsigned decodedCount = 0;
|
unsigned decodedCount = 0;
|
||||||
for (const char* s = encodedStr; *s; ++s)
|
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);
|
EXPECT_EQ(codepoint, decodedCodepoint);
|
||||||
decodedCount++;
|
decodedCount++;
|
||||||
}
|
}
|
||||||
@ -355,7 +354,7 @@ TEST(EncodingsTest, UTF16) {
|
|||||||
unsigned state = 0;
|
unsigned state = 0;
|
||||||
UTF16<>::Ch buffer[3], *p = &buffer[0];
|
UTF16<>::Ch buffer[3], *p = &buffer[0];
|
||||||
for (const char* s = utf8os.GetString(); *s; ++s) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ using namespace rapidjson;
|
|||||||
class FileStreamTest : public ::testing::Test {
|
class FileStreamTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
FileStreamTest() : filename_(), json_(), length_() {}
|
FileStreamTest() : filename_(), json_(), length_() {}
|
||||||
|
virtual ~FileStreamTest();
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
const char *paths[] = {
|
const char *paths[] = {
|
||||||
@ -42,9 +43,9 @@ public:
|
|||||||
ASSERT_TRUE(fp != 0);
|
ASSERT_TRUE(fp != 0);
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
length_ = (size_t)ftell(fp);
|
length_ = static_cast<size_t>(ftell(fp));
|
||||||
fseek(fp, 0, SEEK_SET);
|
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);
|
size_t readLength = fread(json_, 1, length_, fp);
|
||||||
json_[readLength] = '\0';
|
json_[readLength] = '\0';
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -65,6 +66,8 @@ protected:
|
|||||||
size_t length_;
|
size_t length_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FileStreamTest::~FileStreamTest() {}
|
||||||
|
|
||||||
TEST_F(FileStreamTest, FileReadStream) {
|
TEST_F(FileStreamTest, FileReadStream) {
|
||||||
FILE *fp = fopen(filename_, "rb");
|
FILE *fp = fopen(filename_, "rb");
|
||||||
ASSERT_TRUE(fp != 0);
|
ASSERT_TRUE(fp != 0);
|
||||||
|
@ -30,28 +30,28 @@ template <>
|
|||||||
struct Traits<uint32_t> {
|
struct Traits<uint32_t> {
|
||||||
enum { kBufferSize = 11 };
|
enum { kBufferSize = 11 };
|
||||||
enum { kMaxDigit = 10 };
|
enum { kMaxDigit = 10 };
|
||||||
static uint32_t Negate(uint32_t x) { return x; };
|
static uint32_t Negate(uint32_t x) { return x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Traits<int32_t> {
|
struct Traits<int32_t> {
|
||||||
enum { kBufferSize = 12 };
|
enum { kBufferSize = 12 };
|
||||||
enum { kMaxDigit = 10 };
|
enum { kMaxDigit = 10 };
|
||||||
static int32_t Negate(int32_t x) { return -x; };
|
static int32_t Negate(int32_t x) { return -x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Traits<uint64_t> {
|
struct Traits<uint64_t> {
|
||||||
enum { kBufferSize = 21 };
|
enum { kBufferSize = 21 };
|
||||||
enum { kMaxDigit = 20 };
|
enum { kMaxDigit = 20 };
|
||||||
static uint64_t Negate(uint64_t x) { return x; };
|
static uint64_t Negate(uint64_t x) { return x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Traits<int64_t> {
|
struct Traits<int64_t> {
|
||||||
enum { kBufferSize = 22 };
|
enum { kBufferSize = 22 };
|
||||||
enum { kMaxDigit = 20 };
|
enum { kMaxDigit = 20 };
|
||||||
static int64_t Negate(int64_t x) { return -x; };
|
static int64_t Negate(int64_t x) { return -x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -20,16 +20,16 @@ using namespace rapidjson;
|
|||||||
|
|
||||||
static char* ReadFile(const char* filename, size_t& length) {
|
static char* ReadFile(const char* filename, size_t& length) {
|
||||||
const char *paths[] = {
|
const char *paths[] = {
|
||||||
"jsonchecker/%s",
|
"jsonchecker",
|
||||||
"bin/jsonchecker/%s",
|
"bin/jsonchecker",
|
||||||
"../bin/jsonchecker/%s",
|
"../bin/jsonchecker",
|
||||||
"../../bin/jsonchecker/%s",
|
"../../bin/jsonchecker",
|
||||||
"../../../bin/jsonchecker/%s"
|
"../../../bin/jsonchecker"
|
||||||
};
|
};
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
FILE *fp = 0;
|
FILE *fp = 0;
|
||||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
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");
|
fp = fopen(buffer, "rb");
|
||||||
if (fp)
|
if (fp)
|
||||||
break;
|
break;
|
||||||
@ -39,9 +39,9 @@ static char* ReadFile(const char* filename, size_t& length) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
length = (size_t)ftell(fp);
|
length = static_cast<size_t>(ftell(fp));
|
||||||
fseek(fp, 0, SEEK_SET);
|
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);
|
size_t readLength = fread(json, 1, length, fp);
|
||||||
json[readLength] = '\0';
|
json[readLength] = '\0';
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -68,10 +68,10 @@ TEST(JsonChecker, Reader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||||
document.Parse((const char*)json);
|
document.Parse(json);
|
||||||
EXPECT_TRUE(document.HasParseError());
|
EXPECT_TRUE(document.HasParseError());
|
||||||
|
|
||||||
document.Parse<kParseIterativeFlag>((const char*)json);
|
document.Parse<kParseIterativeFlag>(json);
|
||||||
EXPECT_TRUE(document.HasParseError());
|
EXPECT_TRUE(document.HasParseError());
|
||||||
|
|
||||||
free(json);
|
free(json);
|
||||||
@ -88,10 +88,10 @@ TEST(JsonChecker, Reader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||||
document.Parse((const char*)json);
|
document.Parse(json);
|
||||||
EXPECT_FALSE(document.HasParseError());
|
EXPECT_FALSE(document.HasParseError());
|
||||||
|
|
||||||
document.Parse<kParseIterativeFlag>((const char*)json);
|
document.Parse<kParseIterativeFlag>(json);
|
||||||
EXPECT_FALSE(document.HasParseError());
|
EXPECT_FALSE(document.HasParseError());
|
||||||
|
|
||||||
free(json);
|
free(json);
|
||||||
|
@ -312,7 +312,7 @@ TEST(Pointer, Parse_URIFragment) {
|
|||||||
GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
|
GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
|
||||||
EXPECT_TRUE(p.IsValid());
|
EXPECT_TRUE(p.IsValid());
|
||||||
EXPECT_EQ(1u, p.GetTokenCount());
|
EXPECT_EQ(1u, p.GetTokenCount());
|
||||||
EXPECT_EQ(0x00A2, p.GetTokens()[0].name[0]);
|
EXPECT_EQ(static_cast<UTF16<>::Ch>(0x00A2), p.GetTokens()[0].name[0]);
|
||||||
EXPECT_EQ(1u, p.GetTokens()[0].length);
|
EXPECT_EQ(1u, p.GetTokens()[0].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ TEST(Pointer, Parse_URIFragment) {
|
|||||||
GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
|
GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
|
||||||
EXPECT_TRUE(p.IsValid());
|
EXPECT_TRUE(p.IsValid());
|
||||||
EXPECT_EQ(1u, p.GetTokenCount());
|
EXPECT_EQ(1u, p.GetTokenCount());
|
||||||
EXPECT_EQ(0x20AC, p.GetTokens()[0].name[0]);
|
EXPECT_EQ(static_cast<UTF16<>::Ch>(0x20AC), p.GetTokens()[0].name[0]);
|
||||||
EXPECT_EQ(1u, p.GetTokens()[0].length);
|
EXPECT_EQ(1u, p.GetTokens()[0].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1462,3 +1462,38 @@ TEST(Pointer, Ambiguity) {
|
|||||||
EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt());
|
EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/miloyip/rapidjson/issues/483
|
||||||
|
namespace myjson {
|
||||||
|
|
||||||
|
class MyAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = true;
|
||||||
|
void * Malloc(size_t _size) { return malloc(_size); }
|
||||||
|
void * Realloc(void *_org_p, size_t _org_size, size_t _new_size) { (void)_org_size; return realloc(_org_p, _new_size); }
|
||||||
|
static void Free(void *_p) { return free(_p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef rapidjson::GenericDocument<
|
||||||
|
rapidjson::UTF8<>,
|
||||||
|
rapidjson::MemoryPoolAllocator< MyAllocator >,
|
||||||
|
MyAllocator
|
||||||
|
> Document;
|
||||||
|
|
||||||
|
typedef rapidjson::GenericPointer<
|
||||||
|
::myjson::Document::ValueType,
|
||||||
|
MyAllocator
|
||||||
|
> Pointer;
|
||||||
|
|
||||||
|
typedef ::myjson::Document::ValueType Value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Pointer, Issue483) {
|
||||||
|
std::string mystr, path;
|
||||||
|
myjson::Document document;
|
||||||
|
myjson::Value value(rapidjson::kStringType);
|
||||||
|
value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator());
|
||||||
|
myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator());
|
||||||
|
}
|
||||||
|
@ -149,9 +149,9 @@ TEST(PrettyWriter, FileWriteStream) {
|
|||||||
|
|
||||||
fp = fopen(filename, "rb");
|
fp = fopen(filename, "rb");
|
||||||
fseek(fp, 0, SEEK_END);
|
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);
|
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);
|
size_t readLength = fread(json, 1, size, fp);
|
||||||
json[readLength] = '\0';
|
json[readLength] = '\0';
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -25,6 +25,13 @@ using namespace rapidjson;
|
|||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
RAPIDJSON_DIAG_OFF(float-equal)
|
RAPIDJSON_DIAG_OFF(float-equal)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(variadic-macros)
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<bool expect>
|
template<bool expect>
|
||||||
@ -159,12 +166,12 @@ TEST(Reader, ParseNumber_Integer) {
|
|||||||
u.u |= r();
|
u.u |= r();
|
||||||
|
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
if (u.u >= 4294967296ULL) {
|
if (u.u > uint64_t(4294967295u)) {
|
||||||
*internal::u64toa(u.u, buffer) = '\0';
|
*internal::u64toa(u.u, buffer) = '\0';
|
||||||
TEST_INTEGER(ParseUint64Handler, buffer, u.u);
|
TEST_INTEGER(ParseUint64Handler, buffer, u.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u.i <= -2147483649LL) {
|
if (u.i < -int64_t(2147483648u)) {
|
||||||
*internal::i64toa(u.i, buffer) = '\0';
|
*internal::i64toa(u.i, buffer) = '\0';
|
||||||
TEST_INTEGER(ParseInt64Handler, buffer, u.i);
|
TEST_INTEGER(ParseInt64Handler, buffer, u.i);
|
||||||
}
|
}
|
||||||
@ -403,7 +410,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) {
|
|||||||
a = h.actual_;
|
a = h.actual_;
|
||||||
uint64_t bias1 = e.ToBias();
|
uint64_t bias1 = e.ToBias();
|
||||||
uint64_t bias2 = a.ToBias();
|
uint64_t bias2 = a.ToBias();
|
||||||
double ulp = bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1;
|
double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1);
|
||||||
ulpMax = std::max(ulpMax, ulp);
|
ulpMax = std::max(ulpMax, ulp);
|
||||||
ulpSum += ulp;
|
ulpSum += ulp;
|
||||||
}
|
}
|
||||||
@ -456,7 +463,7 @@ struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod
|
|||||||
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
||||||
EXPECT_EQ(0, str_);
|
EXPECT_EQ(0, str_);
|
||||||
if (copy) {
|
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));
|
memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -639,11 +646,11 @@ TEST(Reader, ParseString_Error) {
|
|||||||
{
|
{
|
||||||
char e[] = { '[', '\"', 0, '\"', ']', '\0' };
|
char e[] = { '[', '\"', 0, '\"', ']', '\0' };
|
||||||
for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
|
for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
|
||||||
e[2] = c;
|
e[2] = static_cast<char>(c);
|
||||||
ParseErrorCode error = TestString<UTF8<> >(e);
|
ParseErrorCode error = TestString<UTF8<> >(e);
|
||||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
|
EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
|
||||||
if (error != kParseErrorStringInvalidEncoding)
|
if (error != kParseErrorStringInvalidEncoding)
|
||||||
std::cout << (unsigned)(unsigned char)c << std::endl;
|
std::cout << static_cast<unsigned>(c) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +658,7 @@ TEST(Reader, ParseString_Error) {
|
|||||||
{
|
{
|
||||||
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
|
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
|
||||||
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
|
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
|
||||||
e[2] = (char)c;
|
e[2] = static_cast<char>(c);
|
||||||
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e);
|
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,7 +778,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
|
|||||||
default: ADD_FAILURE(); return false;
|
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 Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
|
||||||
bool String(const char* str, size_t, bool) {
|
bool String(const char* str, size_t, bool) {
|
||||||
switch(step_) {
|
switch(step_) {
|
||||||
@ -1024,15 +1031,15 @@ public:
|
|||||||
|
|
||||||
Ch Peek() const {
|
Ch Peek() const {
|
||||||
int c = is_.peek();
|
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() {
|
Ch Take() {
|
||||||
int c = is_.get();
|
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; }
|
Ch* PutBegin() { assert(false); return 0; }
|
||||||
void Put(Ch) { assert(false); }
|
void Put(Ch) { assert(false); }
|
||||||
@ -1143,7 +1150,7 @@ struct IterativeParsingReaderHandler {
|
|||||||
bool EndObject(SizeType c) {
|
bool EndObject(SizeType c) {
|
||||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||||
Logs[LogCount++] = LOG_ENDOBJECT;
|
Logs[LogCount++] = LOG_ENDOBJECT;
|
||||||
Logs[LogCount++] = (int)c;
|
Logs[LogCount++] = static_cast<int>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,7 +1159,7 @@ struct IterativeParsingReaderHandler {
|
|||||||
bool EndArray(SizeType c) {
|
bool EndArray(SizeType c) {
|
||||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||||
Logs[LogCount++] = LOG_ENDARRAY;
|
Logs[LogCount++] = LOG_ENDARRAY;
|
||||||
Logs[LogCount++] = (int)c;
|
Logs[LogCount++] = static_cast<int>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1349,6 +1356,113 @@ TEST(Reader, ParseTerminationByHandler) {
|
|||||||
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
|
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__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
@ -41,7 +41,7 @@ using namespace rapidjson_simd;
|
|||||||
|
|
||||||
template <typename StreamType>
|
template <typename StreamType>
|
||||||
void TestSkipWhitespace() {
|
void TestSkipWhitespace() {
|
||||||
for (int step = 1; step < 32; step++) {
|
for (size_t step = 1; step < 32; step++) {
|
||||||
char buffer[1025];
|
char buffer[1025];
|
||||||
for (size_t i = 0; i < 1024; i++)
|
for (size_t i = 0; i < 1024; i++)
|
||||||
buffer[i] = " \t\r\n"[i % 4];
|
buffer[i] = " \t\r\n"[i % 4];
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
#include "rapidjson/writer.h"
|
#include "rapidjson/writer.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
TEST(StringBuffer, InitialSize) {
|
TEST(StringBuffer, InitialSize) {
|
||||||
@ -69,6 +74,8 @@ TEST(StringBuffer, Pop) {
|
|||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#if 0 // Many old compiler does not support these. Turn it off temporaily.
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
TEST(StringBuffer, Traits) {
|
TEST(StringBuffer, Traits) {
|
||||||
@ -106,6 +113,8 @@ TEST(StringBuffer, Traits) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(StringBuffer, MoveConstructor) {
|
TEST(StringBuffer, MoveConstructor) {
|
||||||
StringBuffer x;
|
StringBuffer x;
|
||||||
x.Put('A');
|
x.Put('A');
|
||||||
@ -148,3 +157,7 @@ TEST(StringBuffer, MoveAssignment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
#include "rapidjson/internal/strtod.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)
|
#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
|
||||||
|
|
||||||
using namespace rapidjson::internal;
|
using namespace rapidjson::internal;
|
||||||
@ -99,13 +104,13 @@ TEST(Strtod, CheckApproximationCase) {
|
|||||||
EXPECT_EQ(49, hS_Exp5);
|
EXPECT_EQ(49, hS_Exp5);
|
||||||
|
|
||||||
BigInteger dS = BIGINTEGER_LITERAL(dInt);
|
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);
|
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);
|
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("203970822259994138521801764465966248930731085529088") == dS);
|
||||||
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS);
|
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS);
|
||||||
@ -121,3 +126,7 @@ TEST(Strtod, CheckApproximationCase) {
|
|||||||
|
|
||||||
EXPECT_EQ(-1, delta.Compare(hS));
|
EXPECT_EQ(-1, delta.Compare(hS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
@ -15,12 +15,25 @@
|
|||||||
#include "unittest.h"
|
#include "unittest.h"
|
||||||
#include "rapidjson/rapidjson.h"
|
#include "rapidjson/rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#if __has_warning("-Wdeprecated")
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AssertException::~AssertException() throw() {}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
|
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
|
||||||
|
|
||||||
#if _MSC_VER
|
#ifdef _MSC_VER
|
||||||
_CrtMemState memoryState = { 0 };
|
_CrtMemState memoryState = { 0 };
|
||||||
_CrtMemCheckpoint(&memoryState);
|
_CrtMemCheckpoint(&memoryState);
|
||||||
//_CrtSetBreakAlloc(X);
|
//_CrtSetBreakAlloc(X);
|
||||||
@ -29,7 +42,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
int ret = RUN_ALL_TESTS();
|
int ret = RUN_ALL_TESTS();
|
||||||
|
|
||||||
#if _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Current gtest constantly leak 2 blocks at exit
|
// Current gtest constantly leak 2 blocks at exit
|
||||||
_CrtMemDumpAllObjectsSince(&memoryState);
|
_CrtMemDumpAllObjectsSince(&memoryState);
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,10 +15,20 @@
|
|||||||
#ifndef UNITTEST_H_
|
#ifndef UNITTEST_H_
|
||||||
#define UNITTEST_H_
|
#define UNITTEST_H_
|
||||||
|
|
||||||
|
|
||||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||||
#ifndef __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
|
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -41,6 +51,11 @@
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
// All TEST() macro generated this warning, disable globally
|
||||||
|
#pragma GCC diagnostic ignored "-Wglobal-constructors"
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename Ch>
|
template <typename Ch>
|
||||||
inline unsigned StrLen(const Ch* s) {
|
inline unsigned StrLen(const Ch* s) {
|
||||||
const Ch* p = s;
|
const Ch* p = s;
|
||||||
@ -51,19 +66,19 @@ inline unsigned StrLen(const Ch* s) {
|
|||||||
template<typename Ch>
|
template<typename Ch>
|
||||||
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
||||||
while(*s1 && (*s1 == *s2)) { s1++; 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>
|
template <typename Ch>
|
||||||
inline Ch* StrDup(const Ch* str) {
|
inline Ch* StrDup(const Ch* str) {
|
||||||
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
||||||
Ch* buffer = (Ch*)malloc(bufferSize);
|
Ch* buffer = static_cast<Ch*>(malloc(bufferSize));
|
||||||
memcpy(buffer, str, bufferSize);
|
memcpy(buffer, str, bufferSize);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FILE* TempFile(char *filename) {
|
inline FILE* TempFile(char *filename) {
|
||||||
#if _MSC_VER
|
#ifdef _MSC_VER
|
||||||
filename = tmpnam(filename);
|
filename = tmpnam(filename);
|
||||||
|
|
||||||
// For Visual Studio, tmpnam() adds a backslash in front. Remove it.
|
// For Visual Studio, tmpnam() adds a backslash in front. Remove it.
|
||||||
@ -80,15 +95,28 @@ inline FILE* TempFile(char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use exception for catching assert
|
// Use exception for catching assert
|
||||||
#if _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable : 4127)
|
#pragma warning(disable : 4127)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#if __has_warning("-Wdeprecated")
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
class AssertException : public std::logic_error {
|
class AssertException : public std::logic_error {
|
||||||
public:
|
public:
|
||||||
AssertException(const char* w) : std::logic_error(w) {}
|
AssertException(const char* w) : std::logic_error(w) {}
|
||||||
|
AssertException(const AssertException& rhs) : std::logic_error(rhs) {}
|
||||||
|
virtual ~AssertException() throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||||
|
|
||||||
class Random {
|
class Random {
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
#include "rapidjson/document.h"
|
#include "rapidjson/document.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
TEST(Value, DefaultConstructor) {
|
TEST(Value, DefaultConstructor) {
|
||||||
@ -34,6 +39,8 @@ TEST(Value, DefaultConstructor) {
|
|||||||
|
|
||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#if 0 // Many old compiler does not support these. Turn it off temporaily.
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
TEST(Value, Traits) {
|
TEST(Value, Traits) {
|
||||||
@ -72,6 +79,8 @@ TEST(Value, Traits) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(Value, MoveConstructor) {
|
TEST(Value, MoveConstructor) {
|
||||||
typedef GenericValue<UTF8<>, CrtAllocator> Value;
|
typedef GenericValue<UTF8<>, CrtAllocator> Value;
|
||||||
Value::AllocatorType allocator;
|
Value::AllocatorType allocator;
|
||||||
@ -448,7 +457,7 @@ TEST(Value, Uint) {
|
|||||||
|
|
||||||
TEST(Value, Int64) {
|
TEST(Value, Int64) {
|
||||||
// Constructor with int
|
// Constructor with int
|
||||||
Value x(int64_t(1234LL));
|
Value x(int64_t(1234));
|
||||||
EXPECT_EQ(kNumberType, x.GetType());
|
EXPECT_EQ(kNumberType, x.GetType());
|
||||||
EXPECT_EQ(1234, x.GetInt());
|
EXPECT_EQ(1234, x.GetInt());
|
||||||
EXPECT_EQ(1234u, x.GetUint());
|
EXPECT_EQ(1234u, x.GetUint());
|
||||||
@ -469,7 +478,7 @@ TEST(Value, Int64) {
|
|||||||
EXPECT_FALSE(x.IsObject());
|
EXPECT_FALSE(x.IsObject());
|
||||||
EXPECT_FALSE(x.IsArray());
|
EXPECT_FALSE(x.IsArray());
|
||||||
|
|
||||||
Value nx(int64_t(-1234LL));
|
Value nx(int64_t(-1234));
|
||||||
EXPECT_EQ(-1234, nx.GetInt());
|
EXPECT_EQ(-1234, nx.GetInt());
|
||||||
EXPECT_EQ(-1234, nx.GetInt64());
|
EXPECT_EQ(-1234, nx.GetInt64());
|
||||||
EXPECT_TRUE(nx.IsInt());
|
EXPECT_TRUE(nx.IsInt());
|
||||||
@ -482,17 +491,17 @@ TEST(Value, Int64) {
|
|||||||
z.SetInt64(1234);
|
z.SetInt64(1234);
|
||||||
EXPECT_EQ(1234, z.GetInt64());
|
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_FALSE(z.IsInt());
|
||||||
EXPECT_TRUE(z.IsUint());
|
EXPECT_TRUE(z.IsUint());
|
||||||
EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0);
|
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.IsInt());
|
||||||
EXPECT_FALSE(z.IsUint());
|
EXPECT_FALSE(z.IsUint());
|
||||||
EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0);
|
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_FALSE(z.IsInt());
|
||||||
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
|
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
|
||||||
|
|
||||||
@ -502,7 +511,7 @@ TEST(Value, Int64) {
|
|||||||
|
|
||||||
TEST(Value, Uint64) {
|
TEST(Value, Uint64) {
|
||||||
// Constructor with int
|
// Constructor with int
|
||||||
Value x(uint64_t(1234LL));
|
Value x(uint64_t(1234));
|
||||||
EXPECT_EQ(kNumberType, x.GetType());
|
EXPECT_EQ(kNumberType, x.GetType());
|
||||||
EXPECT_EQ(1234, x.GetInt());
|
EXPECT_EQ(1234, x.GetInt());
|
||||||
EXPECT_EQ(1234u, x.GetUint());
|
EXPECT_EQ(1234u, x.GetUint());
|
||||||
@ -528,19 +537,19 @@ TEST(Value, Uint64) {
|
|||||||
z.SetUint64(1234);
|
z.SetUint64(1234);
|
||||||
EXPECT_EQ(1234u, z.GetUint64());
|
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_FALSE(z.IsInt());
|
||||||
EXPECT_TRUE(z.IsUint());
|
EXPECT_TRUE(z.IsUint());
|
||||||
EXPECT_TRUE(z.IsInt64());
|
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.IsInt());
|
||||||
EXPECT_FALSE(z.IsUint());
|
EXPECT_FALSE(z.IsUint());
|
||||||
EXPECT_TRUE(z.IsInt64());
|
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_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());
|
EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +671,7 @@ TEST(Value, String) {
|
|||||||
// SetString()
|
// SetString()
|
||||||
char s[] = "World";
|
char s[] = "World";
|
||||||
Value w;
|
Value w;
|
||||||
w.SetString(s, (SizeType)strlen(s), allocator);
|
w.SetString(s, static_cast<SizeType>(strlen(s)), allocator);
|
||||||
s[0] = '\0';
|
s[0] = '\0';
|
||||||
EXPECT_STREQ("World", w.GetString());
|
EXPECT_STREQ("World", w.GetString());
|
||||||
EXPECT_EQ(5u, w.GetStringLength());
|
EXPECT_EQ(5u, w.GetStringLength());
|
||||||
@ -764,15 +773,15 @@ TEST(Value, Array) {
|
|||||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
// PushBack(GenericValue&&, Allocator&);
|
// PushBack(GenericValue&&, Allocator&);
|
||||||
{
|
{
|
||||||
Value y(kArrayType);
|
Value y2(kArrayType);
|
||||||
y.PushBack(Value(true), allocator);
|
y2.PushBack(Value(true), allocator);
|
||||||
y.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator);
|
y2.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator);
|
||||||
EXPECT_EQ(2u, y.Size());
|
EXPECT_EQ(2u, y2.Size());
|
||||||
EXPECT_TRUE(y[0].IsTrue());
|
EXPECT_TRUE(y2[0].IsTrue());
|
||||||
EXPECT_TRUE(y[1].IsArray());
|
EXPECT_TRUE(y2[1].IsArray());
|
||||||
EXPECT_EQ(2u, y[1].Size());
|
EXPECT_EQ(2u, y2[1].Size());
|
||||||
EXPECT_TRUE(y[1][0].IsInt());
|
EXPECT_TRUE(y2[1][0].IsInt());
|
||||||
EXPECT_TRUE(y[1][1].IsString());
|
EXPECT_TRUE(y2[1][1].IsString());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -841,23 +850,23 @@ TEST(Value, Array) {
|
|||||||
EXPECT_EQ(x.Begin(), itr);
|
EXPECT_EQ(x.Begin(), itr);
|
||||||
EXPECT_EQ(9u, x.Size());
|
EXPECT_EQ(9u, x.Size());
|
||||||
for (int i = 0; i < 9; i++)
|
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
|
// Ease the last
|
||||||
itr = x.Erase(x.End() - 1);
|
itr = x.Erase(x.End() - 1);
|
||||||
EXPECT_EQ(x.End(), itr);
|
EXPECT_EQ(x.End(), itr);
|
||||||
EXPECT_EQ(8u, x.Size());
|
EXPECT_EQ(8u, x.Size());
|
||||||
for (int i = 0; i < 8; i++)
|
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
|
// Erase the middle
|
||||||
itr = x.Erase(x.Begin() + 4);
|
itr = x.Erase(x.Begin() + 4);
|
||||||
EXPECT_EQ(x.Begin() + 4, itr);
|
EXPECT_EQ(x.Begin() + 4, itr);
|
||||||
EXPECT_EQ(7u, x.Size());
|
EXPECT_EQ(7u, x.Size());
|
||||||
for (int i = 0; i < 4; i++)
|
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++)
|
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)
|
// Erase(ValueIterator, ValueIterator)
|
||||||
// Exhaustive test with all 0 <= first < n, first <= last <= n cases
|
// Exhaustive test with all 0 <= first < n, first <= last <= n cases
|
||||||
@ -879,7 +888,7 @@ TEST(Value, Array) {
|
|||||||
for (unsigned i = 0; i < first; i++)
|
for (unsigned i = 0; i < first; i++)
|
||||||
EXPECT_EQ(i, x[i][0].GetUint());
|
EXPECT_EQ(i, x[i][0].GetUint());
|
||||||
for (unsigned i = first; i < n - removeCount; i++)
|
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 +905,7 @@ TEST(Value, Array) {
|
|||||||
x.Erase(std::remove(x.Begin(), x.End(), null), x.End());
|
x.Erase(std::remove(x.Begin(), x.End(), null), x.End());
|
||||||
EXPECT_EQ(5u, x.Size());
|
EXPECT_EQ(5u, x.Size());
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
EXPECT_EQ(i * 2, x[i]);
|
EXPECT_EQ(i * 2, x[static_cast<SizeType>(i)]);
|
||||||
|
|
||||||
// SetArray()
|
// SetArray()
|
||||||
Value z;
|
Value z;
|
||||||
@ -935,8 +944,8 @@ TEST(Value, Object) {
|
|||||||
o.AddMember("false", false, allocator);
|
o.AddMember("false", false, allocator);
|
||||||
o.AddMember("int", -1, allocator);
|
o.AddMember("int", -1, allocator);
|
||||||
o.AddMember("uint", 1u, allocator);
|
o.AddMember("uint", 1u, allocator);
|
||||||
o.AddMember("int64", INT64_C(-4294967296), allocator);
|
o.AddMember("int64", int64_t(-4294967296), allocator);
|
||||||
o.AddMember("uint64", UINT64_C(4294967296), allocator);
|
o.AddMember("uint64", uint64_t(4294967296), allocator);
|
||||||
o.AddMember("double", 3.14, allocator);
|
o.AddMember("double", 3.14, allocator);
|
||||||
o.AddMember("string", "Jelly", allocator);
|
o.AddMember("string", "Jelly", allocator);
|
||||||
|
|
||||||
@ -944,8 +953,8 @@ TEST(Value, Object) {
|
|||||||
EXPECT_FALSE(o["false"].GetBool());
|
EXPECT_FALSE(o["false"].GetBool());
|
||||||
EXPECT_EQ(-1, o["int"].GetInt());
|
EXPECT_EQ(-1, o["int"].GetInt());
|
||||||
EXPECT_EQ(1u, o["uint"].GetUint());
|
EXPECT_EQ(1u, o["uint"].GetUint());
|
||||||
EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64());
|
EXPECT_EQ(int64_t(-4294967296), o["int64"].GetInt64());
|
||||||
EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64());
|
EXPECT_EQ(uint64_t(4294967296), o["uint64"].GetUint64());
|
||||||
EXPECT_STREQ("Jelly",o["string"].GetString());
|
EXPECT_STREQ("Jelly",o["string"].GetString());
|
||||||
EXPECT_EQ(8u, o.MemberCount());
|
EXPECT_EQ(8u, o.MemberCount());
|
||||||
}
|
}
|
||||||
@ -1125,7 +1134,7 @@ TEST(Value, Object) {
|
|||||||
EXPECT_EQ(x.MemberBegin(), itr);
|
EXPECT_EQ(x.MemberBegin(), itr);
|
||||||
EXPECT_EQ(9u, x.MemberCount());
|
EXPECT_EQ(9u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
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_STREQ(itr->name.GetString(), keys[i]);
|
||||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||||
}
|
}
|
||||||
@ -1136,7 +1145,7 @@ TEST(Value, Object) {
|
|||||||
EXPECT_EQ(x.MemberEnd(), itr);
|
EXPECT_EQ(x.MemberEnd(), itr);
|
||||||
EXPECT_EQ(8u, x.MemberCount());
|
EXPECT_EQ(8u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
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_STREQ(itr->name.GetString(), keys[i]);
|
||||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||||
}
|
}
|
||||||
@ -1147,8 +1156,8 @@ TEST(Value, Object) {
|
|||||||
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
||||||
EXPECT_EQ(7u, x.MemberCount());
|
EXPECT_EQ(7u, x.MemberCount());
|
||||||
for (; itr != x.MemberEnd(); ++itr) {
|
for (; itr != x.MemberEnd(); ++itr) {
|
||||||
int i = (itr - x.MemberBegin());
|
size_t i = static_cast<size_t>(itr - x.MemberBegin());
|
||||||
i += (i<4) ? 1 : 2;
|
i += (i < 4) ? 1 : 2;
|
||||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||||
EXPECT_EQ(i, itr->value[0].GetInt());
|
EXPECT_EQ(i, itr->value[0].GetInt());
|
||||||
}
|
}
|
||||||
@ -1162,11 +1171,11 @@ TEST(Value, Object) {
|
|||||||
for (unsigned i = 0; i < n; i++)
|
for (unsigned i = 0; i < n; i++)
|
||||||
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
|
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)
|
if (last == n)
|
||||||
EXPECT_EQ(x.MemberEnd(), itr);
|
EXPECT_EQ(x.MemberEnd(), itr);
|
||||||
else
|
else
|
||||||
EXPECT_EQ(x.MemberBegin() + first, itr);
|
EXPECT_EQ(x.MemberBegin() + static_cast<int>(first), itr);
|
||||||
|
|
||||||
size_t removeCount = last - first;
|
size_t removeCount = last - first;
|
||||||
EXPECT_EQ(n - removeCount, x.MemberCount());
|
EXPECT_EQ(n - removeCount, x.MemberCount());
|
||||||
@ -1214,7 +1223,7 @@ TEST(Value, BigNestedArray) {
|
|||||||
for (SizeType i = 0; i < n; i++) {
|
for (SizeType i = 0; i < n; i++) {
|
||||||
Value y(kArrayType);
|
Value y(kArrayType);
|
||||||
for (SizeType j = 0; j < n; j++) {
|
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);
|
y.PushBack(number, allocator);
|
||||||
}
|
}
|
||||||
x.PushBack(y, allocator);
|
x.PushBack(y, allocator);
|
||||||
@ -1223,7 +1232,7 @@ TEST(Value, BigNestedArray) {
|
|||||||
for (SizeType i = 0; i < n; i++)
|
for (SizeType i = 0; i < n; i++)
|
||||||
for (SizeType j = 0; j < n; j++) {
|
for (SizeType j = 0; j < n; j++) {
|
||||||
EXPECT_TRUE(x[i][j].IsInt());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1237,16 +1246,16 @@ TEST(Value, BigNestedObject) {
|
|||||||
sprintf(name1, "%d", i);
|
sprintf(name1, "%d", i);
|
||||||
|
|
||||||
// Value name(name1); // should not compile
|
// 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);
|
Value object(kObjectType);
|
||||||
|
|
||||||
for (SizeType j = 0; j < n; j++) {
|
for (SizeType j = 0; j < n; j++) {
|
||||||
char name2[10];
|
char name2[10];
|
||||||
sprintf(name2, "%d", j);
|
sprintf(name2, "%d", j);
|
||||||
|
|
||||||
Value name(name2, (SizeType)strlen(name2), allocator);
|
Value name3(name2, static_cast<SizeType>(strlen(name2)), allocator);
|
||||||
Value number((int)(i * n + j));
|
Value number(static_cast<int>(i * n + j));
|
||||||
object.AddMember(name, number, allocator);
|
object.AddMember(name3, number, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// x.AddMember(name1, object, allocator); // should not compile
|
// x.AddMember(name1, object, allocator); // should not compile
|
||||||
@ -1261,7 +1270,7 @@ TEST(Value, BigNestedObject) {
|
|||||||
char name2[10];
|
char name2[10];
|
||||||
sprintf(name2, "%d", j);
|
sprintf(name2, "%d", j);
|
||||||
x[name1];
|
x[name1];
|
||||||
EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt());
|
EXPECT_EQ(static_cast<int>(i * n + j), x[name1][name2].GetInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1293,7 +1302,7 @@ TEST(Document, CrtAllocator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TestShortStringOptimization(const char* str) {
|
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::Document doc;
|
||||||
rapidjson::Value val;
|
rapidjson::Value val;
|
||||||
@ -1354,3 +1363,27 @@ TEST(Value, AcceptTerminationByHandler) {
|
|||||||
TEST_TERMINATION(11, "{\"a\":[]}");
|
TEST_TERMINATION(11, "{\"a\":[]}");
|
||||||
TEST_TERMINATION(12, "{\"a\":[]}");
|
TEST_TERMINATION(12, "{\"a\":[]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ValueIntComparer {
|
||||||
|
bool operator()(const Value& lhs, const Value& rhs) const {
|
||||||
|
return lhs.GetInt() < rhs.GetInt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
TEST(Value, Sorting) {
|
||||||
|
Value::AllocatorType allocator;
|
||||||
|
Value a(kArrayType);
|
||||||
|
a.PushBack(5, allocator);
|
||||||
|
a.PushBack(1, allocator);
|
||||||
|
a.PushBack(3, allocator);
|
||||||
|
std::sort(a.Begin(), a.End(), ValueIntComparer());
|
||||||
|
EXPECT_EQ(1, a[0].GetInt());
|
||||||
|
EXPECT_EQ(3, a[1].GetInt());
|
||||||
|
EXPECT_EQ(5, a[2].GetInt());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
@ -66,7 +66,7 @@ gh_pages_prepare()
|
|||||||
[ ! -d "html" ] || \
|
[ ! -d "html" ] || \
|
||||||
abort "Doxygen target directory already exists."
|
abort "Doxygen target directory already exists."
|
||||||
git --version
|
git --version
|
||||||
git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html
|
git clone -b gh-pages "${GITHUB_CLONE}" html
|
||||||
cd html
|
cd html
|
||||||
# setup git config (with defaults)
|
# setup git config (with defaults)
|
||||||
git config user.name "${GIT_NAME-travis}"
|
git config user.name "${GIT_NAME-travis}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user