Merge branch 'master' into schema

# Conflicts:
#	.gitignore
#	include/rapidjson/internal/stack.h
This commit is contained in:
Milo Yip 2016-01-26 15:24:04 +08:00
commit 7f9921fc60
75 changed files with 2011 additions and 580 deletions

9
.gitignore vendored
View File

@ -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

View File

@ -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"

View File

@ -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

Binary file not shown.

BIN
bin/types/floats.json Executable file

Binary file not shown.

BIN
bin/types/guids.json Executable file

Binary file not shown.

BIN
bin/types/integers.json Executable file

Binary file not shown.

BIN
bin/types/mixed.json Executable file

Binary file not shown.

BIN
bin/types/nulls.json Executable file

Binary file not shown.

BIN
bin/types/paragraphs.json Executable file

Binary file not shown.

1
bin/types/readme.txt Normal file
View File

@ -0,0 +1 @@
Test data obtained from https://github.com/xpol/lua-rapidjson/tree/master/performance

View File

@ -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

View File

@ -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.

View File

@ -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++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。

View File

@ -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)

View File

@ -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. 什么是转移语意?为什么?

View File

@ -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

View File

@ -23,6 +23,8 @@
* 支持Unicod代理对surrogate pair * 支持Unicod代理对surrogate pair
* 支持空字符(`"\u0000"`)。 * 支持空字符(`"\u0000"`)。
* 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。 * 例如,可以优雅地解析及处理`["Hello\u0000World"]`。含读写字符串长度的API。
* 支持放宽的可选语法
* 单行(`// ...`)及多行(`/* ... */` 注释。
## Unicode ## Unicode

View File

@ -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
View File

@ -0,0 +1,234 @@
# Pointer
## 状态: 实验性,应该会合进 v1.1
JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON DocumentDOM中的值。这类似于 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

View File

@ -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更容易实现。

View File

@ -2,7 +2,7 @@
本教程简介文件对象模型Document Object Model, DOMAPI。 本教程简介文件对象模型Document Object Model, DOMAPI。
如[用法一览](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)`:移除一个范围内的成员,维持次序(线性时间复杂度)。

View File

@ -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()

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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());

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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;
} }

View File

@ -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

View File

@ -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:

View File

@ -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_

View File

@ -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;

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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_;

View File

@ -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);
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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_

View File

@ -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
View 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;
};
}

View File

@ -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:

View File

@ -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)

View File

@ -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;
}; };

View File

@ -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

View File

@ -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()

View File

@ -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
}

View File

@ -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

View File

@ -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");

View File

@ -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;
} }

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -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());
}

View File

@ -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);

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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}"